changeset 0:241c93442be0 yadex-1_7_0

Initial import.
author Matti Hamalainen <ccr@tnsp.org>
date Wed, 21 Sep 2011 04:30:44 +0300
parents
children bb0c840d1bf2
files CHANGES COPYING COPYING.LIB FAQ GNUmakefile Makefile README TODO VERSION atclib/al_adigits.c atclib/al_aerrno.c atclib/al_astrerror.c atclib/al_fana.c atclib/al_fnature.c atclib/al_lateol.c atclib/al_lcount.c atclib/al_lcreate.c atclib/al_ldelete.c atclib/al_ldiscard.c atclib/al_lgetpos.c atclib/al_linsert.c atclib/al_linsertl.c atclib/al_llength.c atclib/al_lpeek.c atclib/al_lpeekl.c atclib/al_lpoke.c atclib/al_lpokel.c atclib/al_lptr.c atclib/al_lread.c atclib/al_lreadl.c atclib/al_lrewind.c atclib/al_lseek.c atclib/al_lsetpos.c atclib/al_lstep.c atclib/al_ltell.c atclib/al_lwrite.c atclib/al_lwritel.c atclib/al_sapc.c atclib/al_saps.c atclib/al_scps.c atclib/al_scpslower.c atclib/al_sdup.c atclib/al_sisnum.c atclib/al_strolc.c atclib/atclib.h boost/boost/config.hpp boost/boost/config/compiler/borland.hpp boost/boost/config/compiler/comeau.hpp boost/boost/config/compiler/common_edg.hpp boost/boost/config/compiler/compaq_cxx.hpp boost/boost/config/compiler/gcc.hpp boost/boost/config/compiler/greenhills.hpp boost/boost/config/compiler/hp_acc.hpp boost/boost/config/compiler/intel.hpp boost/boost/config/compiler/kai.hpp boost/boost/config/compiler/metrowerks.hpp boost/boost/config/compiler/mpw.hpp boost/boost/config/compiler/sgi_mipspro.hpp boost/boost/config/compiler/sunpro_cc.hpp boost/boost/config/compiler/vacpp.hpp boost/boost/config/compiler/visualc.hpp boost/boost/config/platform/aix.hpp boost/boost/config/platform/beos.hpp boost/boost/config/platform/bsd.hpp boost/boost/config/platform/cygwin.hpp boost/boost/config/platform/hpux.hpp boost/boost/config/platform/irix.hpp boost/boost/config/platform/linux.hpp boost/boost/config/platform/macos.hpp boost/boost/config/platform/solaris.hpp boost/boost/config/platform/win32.hpp boost/boost/config/posix_features.hpp boost/boost/config/select_compiler_config.hpp boost/boost/config/select_platform_config.hpp boost/boost/config/select_stdlib_config.hpp boost/boost/config/stdlib/dinkumware.hpp boost/boost/config/stdlib/libstdcpp3.hpp boost/boost/config/stdlib/modena.hpp boost/boost/config/stdlib/msl.hpp boost/boost/config/stdlib/roguewave.hpp boost/boost/config/stdlib/sgi.hpp boost/boost/config/stdlib/stlport.hpp boost/boost/config/stdlib/vacpp.hpp boost/boost/config/suffix.hpp boost/boost/config/user.hpp boost/boost/smart_ptr.hpp boost/boost/static_assert.hpp boost/boost/utility.hpp boost/boost/utility/base_from_member.hpp boost/boost/utility_fwd.hpp cache/copyright.man cache/copyright.txt cache/pixlist cache/srcdate cache/uptodate configure doc/README docsrc/002f2f.png docsrc/E1.png docsrc/E2.png docsrc/README docsrc/README.doc docsrc/advanced.html docsrc/contact.html docsrc/copyright docsrc/credits.html docsrc/deu_diffs.html docsrc/e1.png docsrc/e2.png docsrc/editing_docs.html docsrc/faq.html docsrc/feedback.html docsrc/getting_started.html docsrc/hackers_guide.html docsrc/help.html docsrc/index.html docsrc/keeping_up.html docsrc/legal.html docsrc/logo.png docsrc/logo_small.png docsrc/mirror0.png docsrc/mirrorh.png docsrc/mirrorv.png docsrc/nook1.png docsrc/nook2.png docsrc/packagers_guide.html docsrc/palette.html docsrc/reporting.html docsrc/slice1.png docsrc/slice2.png docsrc/tips.html docsrc/trivia.html docsrc/trouble.html docsrc/users_guide.html docsrc/vflat.png docsrc/vsprite.png docsrc/vtexture.png docsrc/wad_specs.html docsrc/yadex.6 docsrc/yadex1.png docsrc/ygd.html patches/1.5.0_gcc27.diff patches/README scripts/copyright scripts/ftime.1 scripts/ftime.c scripts/install.c scripts/mkinstalldirs scripts/notexist.c scripts/process scripts/youngest src/_edit.h src/acolours.cc src/acolours.h src/aym.cc src/aym.h src/bench.cc src/bench.h src/bitvec.cc src/bitvec.h src/cfgfile.cc src/cfgfile.h src/checks.cc src/checks.h src/colour.h src/colour1.cc src/colour2.cc src/colour3.cc src/colour4.cc src/credits.cc src/credits.h src/dependcy.cc src/dependcy.h src/dialog.cc src/dialog.h src/disppic.cc src/disppic.h src/drawmap.cc src/drawmap.h src/edisplay.cc src/edisplay.h src/editgrid.cc src/editgrid.h src/editlev.cc src/editlev.h src/editloop.cc src/editloop.h src/editobj.cc src/editobj.h src/editsave.cc src/editsave.h src/editzoom.cc src/editzoom.h src/edwidget.h src/endian.cc src/endian.h src/entry.cc src/entry.h src/entry2.cc src/entry2.h src/events.cc src/events.h src/flats.cc src/flats.h src/game.cc src/game.h src/gamedef.h src/gamesky.h src/gcolour1.cc src/gcolour1.h src/gcolour2.cc src/gcolour2.h src/gcolour3.cc src/gcolour3.h src/geom.cc src/gfx.cc src/gfx.h src/gfx2.cc src/gfx2.h src/gfx3.cc src/gfx3.h src/gotoobj.cc src/gotoobj.h src/help1.cc src/help1.h src/help2.cc src/help2.h src/highlt.cc src/highlt.h src/img.cc src/img.h src/imgscale.cc src/imgscale.h src/imgspect.cc src/imgspect.h src/infobar.cc src/infobar.h src/input.cc src/input.h src/l_align.cc src/l_centre.cc src/l_centre.h src/l_flags.cc src/l_flags.h src/l_misc.cc src/l_prop.cc src/l_super.h src/l_unlink.cc src/l_vertices.cc src/l_vertices.h src/levels.cc src/levels.h src/lists.cc src/lists.h src/locate.cc src/locate.h src/lumpdir.cc src/lumpdir.h src/macro.cc src/macro.h src/masterdir.h src/memory.cc src/menu.cc src/menu.h src/menubar.cc src/menubar.h src/menudata.h src/mkpalette.cc src/mkpalette.h src/modpopup.h src/mouse.cc src/names.cc src/nop.cc src/objects.cc src/objects.h src/objid.h src/objinfo.cc src/objinfo.h src/oldmenus.cc src/oldmenus.h src/palview.cc src/palview.h src/patchdir.cc src/patchdir.h src/pic2img.cc src/pic2img.h src/prefer.cc src/prefer.h src/record.h src/rgb.h src/rgbbmp.h src/s_centre.cc src/s_centre.h src/s_door.cc src/s_lift.cc src/s_linedefs.cc src/s_linedefs.h src/s_merge.cc src/s_misc.cc src/s_prop.cc src/s_slice.cc src/s_slice.h src/s_split.cc src/s_swapf.cc src/s_swapf.h src/s_vertices.cc src/s_vertices.h src/sanity.cc src/sanity.h src/scrnshot.cc src/selbox.cc src/selbox.h src/selectn.cc src/selectn.h src/selpath.cc src/selpath.h src/selrect.cc src/serialnum.cc src/serialnum.h src/spot.h src/spritdir.cc src/spritdir.h src/sticker.cc src/sticker.h src/swapmem.cc src/t_centre.cc src/t_centre.h src/t_flags.cc src/t_flags.h src/t_prop.cc src/t_spin.cc src/t_spin.h src/textures.cc src/textures.h src/things.cc src/things.h src/trace.cc src/trace.h src/v_centre.cc src/v_centre.h src/v_merge.cc src/v_polyg.cc src/vectext.cc src/vectext.h src/verbmsg.cc src/version.cc src/wadfile.cc src/wadfile.h src/wadlist.cc src/wadlist.h src/wadname.h src/wadnamec.cc src/wadnamec.h src/wadres.cc src/wadres.h src/wads.cc src/wads.h src/wads2.cc src/wads2.h src/warn.cc src/windim.cc src/windim.h src/wstructs.h src/x11.cc src/x11.h src/x_centre.cc src/x_centre.h src/x_exchng.cc src/x_exchng.h src/x_hover.cc src/x_hover.h src/x_mirror.cc src/x_mirror.h src/x_rotate.cc src/x_rotate.h src/xref.cc src/xref.h src/yadex.cc src/yadex.h src/yerror.h src/ymemory.h src/ytime.cc src/ytime.h yadex.cfg yadex.dep ygd/doom.ygd ygd/doom02.ygd ygd/doom04.ygd ygd/doom05.ygd ygd/doom2.ygd ygd/doompr.ygd ygd/heretic.ygd ygd/hexen.ygd ygd/strife.ygd ygd/strife10.ygd
diffstat 395 files changed, 67483 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CHANGES	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,1475 @@
+Changes
+
+Yadex 1.7.0 (2003-12-28)
+
+  * Build: The configure script autodetects the C and C++ compiler (cc,
+    c89 or gcc and c++, cxx or g++). To skip the detection and force a
+    particular value, use the --cc and --cxx options.
+
+  * Code: Minor warningectomy. Fixed potential uses of uninitialised
+    pointers if wad I/O errors occurred while reading the texture list.
+
+  * Editing: Improved the handling of superimposed objects.
+      + The linedef object info box now lists any superimposed linedefs
+        (up to seven). No such feature for vertices, sectors and
+        things, mainly because it doesn't seem to be as big an issue
+        and I'm lazy.
+      + When the pointer is over more than one object, it's now the
+        highest-numbered one that's highlighted and not the
+        lowest-numbered as it used to be. Thus the highlight and the
+        info box match the display (that shows the highest-numbered
+        object and always has), which should be less confusing.
+        Highlighting the highest-numbered object seems to be the right
+        thing too, since the object you created last is the one you're
+        most likely to want to edit or delete. This change only affects
+        vertices, linedefs and things. For sectors, the code hasn't
+        changed.
+
+  * Game/wad: Heretic: correct definitions for linedef types 28, 33,
+    99, 105, 107-141 and sector types 4, 21-51, courtesy of Barry Mead.
+    Correct definitions for linedef types 35, 40, 100 and 106 and
+    sector type 11.
+
+  * Game/wad: Doom (all versions), Heretic and Strife:
+      + Linedef type 68 is now described as "raise floor" and not
+        "lower floor". This error can be traced back to... DEU 5.21.
+      + Linedef types 36 and 98 are now described as "lower turbo
+        floor" instead of "lower floor fast". The UDS inaccurately list
+        these types (as well as 70 and 71) as "fast", even though
+        they're "turbo" (4 × FLOORSPEED).
+      + Linedef types 70 and 71 are now described as "lower turbo
+        floor" instead of just "lower floor". This one is all mine.
+      + Linedef types 35 and 79 are now described as "light level goes
+        to 35", not "light level goes to 0". The UDS needs a
+        correction.
+
+    Thanks to Barry Mead for pointing out these errors.
+
+  * Misc: Finished the alternative (black-on-white) colour scheme. To
+    use it, compile with CXXFLAGS=-DWHITE_BACKGROUND. There are a few
+    remaining problems in view*.
+
+  * Misc: Fixed geometry problems in Input2Numbers() (as used in Rotate
+    And Scale Objects, Insert Rectangle, etc.).
+
+Yadex 1.6.0 (2003-04-01)
+
+  * BSP: Removed the old buggy patched up BSP 2.3. People should
+    download BSP 5 from http://doombsp.sourceforge.net/, which is a
+    much better nodes builder.
+
+  * Build: Changed the "! grep" command in the makefile so that it does
+    not match itself. Also added a dummy "true;" in front of it because
+    GNU make 3.76.1 does not seem to like commands that begin with "!"
+    (says "Error 1" and bails out).
+
+  * Build: Removed the empty lines in the makefile's output. Small
+    fixes w.r.t. $(HAVE_GCC), "make showconf" and elsewhere.
+
+  * Build: As scripts/ftime can't be shared across builds, it's now put
+    in obj/0/, making it possible to build for different architectures
+    from the same tree without having to type "make clean" between the
+    builds.
+
+  * Build: Not using "test -e" anymore in the makefile. This should fix
+    build problems on OpenServer, UnixWare, Solaris and other unices
+    with a non-POSIX /bin/sh. Thanks to Udo Munk and Oliver Kraus for
+    telling me about it.
+
+  * Build: "make clean" and "make dclean" now remove obj and dobj
+    respectively. This is for UnixWare where reportedly "ln -sf" does
+    not overwrite dangling symlinks. Thanks to Udo Munk for warning me
+    about it.
+
+  * Build: "make clean" now removes the doc directory as suggested by
+    Udo Munk.
+
+  * Build: The man page is now named yadex-VERSION. "yadex" is a
+    symlink to the above. This means that the day you install version
+    1.7, you will still have access to the man page of version 1.6 by
+    typing "man yadex-1.6.0".
+
+  * Build: The system fingerprint is now much shorter to avoid build
+    errors on QNX where the native fs limits file names to 48
+    characters.
+
+  * Build: Files installed by "make install" are now owned by the user
+    who ran "make install", instead of the user who ran "make".
+    Typically, when installing in /usr/local, files are now owned by
+    something like root:root instead of user:user.
+
+  * Build: Files installed by "make install" now have their mode forced
+    to something sensible (i.e. 755 or 644), regardless of whatever
+    umask the users who built and installed happen to have.
+
+  * Build: Use "rm -f new && ln -s old new" instead of "ln -sf old new"
+    for compatibility with Solaris 2.6 where reportedly "ln -sf" does
+    not overwrite the destination.
+
+  * Build: New configure script. "Not the famous GNU autoconf, but an
+    incredible simulation".
+
+    Installing in an other directory than /usr/local is now done by
+    giving ./configure the --prefix option. The old method (overriding
+    the PREFIX makefile variable) is not supported anymore.
+
+    Some configuration variables (whether gettimeofday(), nanosleep(),
+    snprintf() and usleep() are present) are now detected automatically
+    by configure.
+
+    Others (CFLAGS, CXXFLAGS, LDFLAGS, X11LIBDIR and X11INCLUDEDIR) are
+    still set in the Makefile.
+
+  * Build: Removed the merging of stderr with stdout from the makefile
+    recipes. It was just a commodity and nobody else does that.
+
+  * Build: The compilation and linking recipes in the makefile now
+    print the actual commands being run. Now that the defines are
+    passed via config.h and not on the command line, command length is
+    not as big an issue as it used to be.
+
+  * Code: Changed the input event type from int to unsigned short to
+    avoid wasting too much space in the menus.
+
+  * Code: Fixed bug in hextoi() : due to a typo, upper case letters in
+    hexadecimal numbers were evaluated to 75 instead of 10 through 15.
+
+  * Code: Used mkstemp() instead of tempnam() to shut warning on
+    FreeBSD (thanks to Colin Phipps for the report) and with recent
+    versions of Glibc. While I was at it, changed the temporary file
+    name prefix from "{DEU}" to "$TMPDIR/yadexswp??????" (or "/tmp/
+    yadexswp??????" if $TMPDIR is not set).
+
+  * Code: Certain variables have been changed from integer to unsigned
+    integer. Better syntax checking for unsigned integers. Trailing
+    spaces no longer cause syntax errors.
+
+  * Code: The diff distribution is now made with "diff -a" to cope with
+    binary files that change between versions. Thanks to Ouafae Kotby
+    and Benjamin Bayart for telling me about this flag.
+
+  * Code: The diff distribution is now a single gzipped file instead of
+    a tarball (the README has been inlined).
+
+  * Code: Changed all occurrences of "gray" to "grey" since apparently
+    "gray" is an americanism.
+
+  * Code: Fixed bug in Img::resize() when new width × height was the
+    same as old width × height. Spotted by IvL.
+
+  * Code: Fixed x/y mix-up in DrawScreenText(). Spotted by IvL.
+
+  * Code: Protected against inadvertent assignment or copy-construction
+    of classes for which those actions are not implemented by declaring
+    the corresponding methods private and not defining them.
+
+  * Code: Removed non-portable "t" fopen() mode qualifiers.
+
+  * Command-line: Options --help and --version now check for write
+    errors and exit with a non zero status should the occasion arise.
+
+  * Doc: FAQ fixes. Updated the "supported games" section.
+    Clarifications, additions and corrections in the misc. op.
+    sections.
+
+  * Doc: The welcome banner suggests "c" (instead of "c levelname"
+    which is not implemented).
+
+  * Doc: Added complete copyright information to the man page and
+    "about" box. Author section in man page now gives proper credit to
+    contributors.
+
+  * Doc: Updates to the hacker's guide.
+
+  * Doc: s/ftp.cdrom.com/3darchives.in-span.net/g
+
+  * Doc: users_guide.html has numbered heading and working links in the
+    TOC. Overhauled the sections about configuration and game
+    definition files.
+
+  * Editing: Make linedef single-sided: the lower and upper texture are
+    cleared. The middle texture is set to the default.
+
+  * Editing: Found a funny bug; if you tried to highlight a
+    way-off-screen sector at a high (> 3) zoom factor, sometimes the
+    sector actually appeared on the window, even though it was supposed
+    to be a few thousand pixels off-screen. I don't know if the
+    "oddity" is in Xlib, in the X server or in my video card but,
+    interestingly, the symptoms show up only when drawing horizontal or
+    vertical lines on the window, not when drawing oblique lines or on
+    the pixmap.
+
+    Since it only occurs at high zoom factors, it must be some sort of
+    overflow error though it doesn't look like a 32-bit value being
+    truncated to 16 bits because the values are too small. Strange. I
+    dumbly worked around it by skipping off-screen objects.
+
+  * Editing: A linedef, thing or vertex is highlighted if the pointer
+    is within 15 pixels of it. Previously, the threshold was 20 map
+    units which was too narrow at low zoom factors and too broad at
+    high zoom factors. This change makes drawing selection boxes in
+    crowded areas much easier than before.
+
+  * Editing: Configuration variables thing_fudge and vertex_fudge are
+    gone, since they've been made irrelevant by changes in the
+    highlighting code.
+
+  * Editing: If the pointer is within highlighting distance of more
+    than one thing, the one that is highlighted is the one in which the
+    pointer is, or the one that has the smallest radius, or the one
+    whose centre is nearest. Previously, the lowest-numbered one was
+    highlighted, making it impossible to select, say, a high numbered
+    baron standing in the same spot as an arachnotron.
+
+  * Editing: Restored [Shift][Ins] that was inadvertently disabled
+    during the port to X. Thanks to Ingo van Lil for reporting this
+    bug.
+
+  * Editing: If a linedef has a negative tag, tagged sectors are now
+    shown.
+
+  * Editing: As per Ingo van Lil's suggestion, if a linedef is tagged
+    to more than one sector, a "+" is appended to the sector number in
+    the object info window. Similarly, if a sector is tagged to more
+    than one linedef, a "+" is appended to the linedef number in the
+    object info window.
+
+  * Editing: In the object info window, tag 667 is now marked as
+    special. Yadex catches up with that newfangled Doom II thing.
+
+  * Editing: The static text in the object info boxes is now a bit
+    dimmer to make the important information stand out.
+
+  * Editing: Started working on a global mode, where you can work with
+    all types of objects at once, vertices, linedefs, sectors and
+    things. It's toggled by pressing [Ctrl][g] in the editing window.
+    Since it's an experimental feature, it comes with a big fat
+    warning, that you should take seriously. One known bug is that
+    selection is broken is this mode. Overhauled GetCurObject() to make
+    it able to cope with global mode.
+
+  * Editing: [1] through [9] and [0] are now configurable through the
+    new variables "digit_zoom_base" and "digit_zoom_step". The default
+    values are set to roughly emulate the old behaviour but it's now
+    possible to have the zoom factor increase across the keyboard, for
+    instance. Patch by AJA.
+
+  * Editing: New variable "blindly_swap_sidedefs" to prevent Yadex from
+    asking for confirmation when swapping sidedefs. Patch by AJA.
+
+  * Editing: Placeat AJA, it's now possible to toggle the object info
+    boxes with [i]. Toggling the info bar is now bound to [Alt][i].
+
+  * Editing: The "Info bar" item has been moved from the "Help" menu to
+    the "View" menu. Fixed misplaced underscore in linedef "Misc" menu.
+    Fixed misplaced tick marks (thanks to Ingo van Lil) and added
+    separations in the "View" menu. Added missing ellipses here and
+    there.
+
+  * Editing: Removed the sudden jump (down) in the size of the vertices
+    when zooming in.
+
+  * Editing: Sectors are now shown in one of three colours : green for
+    sectors that have a tag, blue for sectors that have a type and cyan
+    for sectors that have both. Previously, all tagged sectors looked
+    the same, whether they had a type or not.
+
+  * Editing: Integer entry: you can now enter hexadecimal or octal
+    numbers by prefixing them with "0x" or "0", as in C. This should
+    make it easier to enter Boom generalized types. You are now allowed
+    to start the number with an explicit plus sign ("+"). The lower
+    limit has been pushed from -32,749 to -32,768. The upper limit has
+    been pushed from +32,749 to +32,767. For consistency with the rest
+    of the interface, if the current entry is invalid, it is shown in
+    red instead of dim grey. You are allowed to type more characters,
+    even if the current entry is invalid ([Return] is still disabled,
+    however). The message in InputIntegerValue() has been changed from
+    "Enter a decimal number" to "Enter a number".
+
+  * Editing: Fixed segfault on "Save as..." on a new level (i.e. opened
+    with the "create" command). This bug was there ever since 1.1.
+
+  * Editing: On a new level (opened with the "create" command), the
+    level name and file name are now remembered so you don't have to
+    enter them again every time you save.
+
+  * Editing: New function "cut a slice out of a sector" to easily split
+    doughnut-shaped sectors. Shortcut is [Ctrl][k]. See
+    users_guide.html for details. Thanks to Jim Flynn for writing a
+    similar function in DETH, which I used as a reference.
+
+  * Editing: Setting things flags by value now allows any value between
+    0 and 65,535 (instead of 1 through 31). The word "decimal" has been
+    removed from the menu item since you can now enter hexadecimal as
+    well.
+
+  * Editing: [n], [p], [<] and [>] work properly even if no object was
+    highlighted.
+
+  * Editing: In linedef mode, linedefs that have no first sidedef, or a
+    bad sidedef number are drawn in red.
+
+  * Game/wad: MBF: changed the radius of the dog from 16 to 12. Thanks
+    to AJA for pointing it out.
+
+  * Game/wad: Boom: added all of Boom's 130 non-generalized linedef
+    types to doom.ygd and doom2.ygd. New "elevator" linedef type group.
+    Many thanks to AJA for typing in the ygd data.
+
+  * Game/wad: Linedef types 33 and 34 were incorrectly labelled "yel"
+    and "red" instead of the other way around. Thanks to Ingo van Lil
+    for pointing this out.
+
+  * Game/wad: Linedef type 96 was incorrectly marked "W1" instead of
+    "WR". Spotted by IvL.
+
+  * Game/wad: Hexen: added to hexen.ygd a couple of things types and
+    most sector and linedef types. Linedefs now have their tag set to
+    arg1. It used to be left uninitialized, which is why so many
+    linedefs were shown in red on the map.
+
+  * Game/wad: Linedef types 105 and 111 had their descriptions
+    reversed. Don't blindly trust the UDS. Spotted by AJA.
+
+  * Game/wad: Gave a sprite to Doom thing type 23 (dead lost soul),
+    SKULK.
+
+  * Game/wad: Strife: definitions for thing types 10, 27, 46, 50, 81,
+    137, 138, 2018, 2019 and 2026.
+
+  * Game/wad: Hexen: definitions for things 122, 124 and 8004.
+
+  * Misc: Flat/patch/sprite/texture viewer: restored ability to save to
+    file by pressing [Shift][F1].
+
+  * Misc: Flat/patch/sprite/texture viewer: not unnecessarily
+    refreshing the whole image window anymore when browsing patches or
+    sprites.
+
+  * Misc: Texture viewer: new bindings [Ctrl][a] [Ctrl][x] to change
+    the number of patches shown.
+
+  * Misc: Most I/O errors occurring while reading wads are now handled
+    gracefully (fewer gratuitous calls to fatal_error()).
+
+  * Misc: The menu code (menu.cc and oldmenus.cc) has been partly
+    rewritten. Made the automatic shortcuts case-sensitive to allow up
+    to 61 entries instead of just 35. Option numbers shortcuts are
+    framed with dimmer square brackets, instead of parentheses.
+    Implemented separations. Two extra pixels of space between lines.
+    Tick marks now look like tick marks, not asterisks. Unticked
+    entries now have a dash in front of them.
+
+  * Misc: The search paths for game definition files and configuration
+    files have changed in several ways.
+
+    Some config file search directories have changed for conformance to
+    the FHS. If the prefix is "/usr/local", the path is now "/etc/
+    yadex" instead of "/usr/local/etc/yadex". If the prefix is "/opt/
+    something", the path is now "/etc/opt/something" instead of "/opt/
+    something/etc/yadex". The practical consequence for the 90% of you
+    who install in /usr/local is that the system-wide config file has
+    moved from /usr/local/etc to /etc.
+
+    Overriding the prefix now actually works for other prefixes than /
+    usr and /usr/local. The problem was that, even though the makefile
+    installed the files in the proper directories, the yadex binary
+    looked for them in /etc, /usr and /usr/local, regardless of the
+    prefix. Thanks to Oliver Kraus and Udo Munk for clueing me in.
+
+    Yadex used to look for files in places where it shouldn't have. For
+    example, it looked for game definition files in /usr even if
+    compiled for /usr/local and vice-versa. Yadex now looks for files
+    only in the places corresponding to the prefix it was compiled for.
+    This makes it possible to have several builds of the same version
+    of Yadex on the same machine without unwanted interactions, as long
+    as they're compiled for different prefixes. Note, however, that /
+    etc/yadex is used by both /usr and /usr/local but that is mandated
+    by the FHS and there's nothing I can do.
+
+    The search directories relative to $YADEX_DIR have been removed
+    from the Unix version (they were intended for DOS).
+
+    See users_guide.html for the exact contents of the new search
+    paths.
+
+  * Misc: Config file: bumped the config file version# from 3 to 4.
+
+  * Misc: Fixed strange reactions to percent character ("%") in the
+    file name entry box.
+
+  * Misc: Slightly less chaotic output in verbose mode.
+
+  * Misc: Fixed a memory leak that occurred when repeatedly reloading a
+    wad. This log entry is particularly delightful because that leak
+    was introduced by me in version 1.5.0 while trying to fix a bug in
+    the same code that was, guess what, an fd leak. For the
+    historically minded, that fd leak goes back to at least DEU 5.21.
+    Try it. It's easily exercised by loading the same wad over and
+    over. After about 20 iterations, you are rewarded with "patch wad
+    file xxx doesn't exist. Ignored.".
+
+  * Misc: Removed from the makefile unflattering comments on bzip2's
+    celerity that came from using an old version.
+
+  * Misc: Decapitalised object type names (GetObjectTypeName()).
+
+  * Misc: Fixed display bug in sector# and sidedef# entry box
+    (InputObjectXref()).
+
+  * Misc: The config file search algorithm has been modified to support
+    multiple config files. The old algorithm was to walk the search
+    path front to back and stop at the first match. The new algorithm
+    is to walk the path back to front and use all the matches. Thus
+    local files inherit parameter settings from global files and still
+    have the possibility to selectively override them (i.e. you can
+    override some parameters and inherit the others).
+
+    For example, assuming /etc/yadex/1.6.0/yadex.cfg contains :
+
+        a = old
+        b = old
+
+    and ./yadex.cfg contains :
+
+        a = new
+        c = new
+
+    the net effect is :
+
+        a = new
+        b = old
+        c = new
+
+    The motivation for the change was to allow users to put most of
+    their settings in global config files, either system wide or
+    per-user. When local files exist, they should contain only the
+    minimum, i.e. just those settings you want to override. This way of
+    doing has several advantages over the previous all-or-nothing
+    system. Obviously, you can now change a setting globally by editing
+    just one file, even if you have many local config files. Upgrades
+    are also smoother because any new variable definitions appearing in
+    global config files propagate even if local config files exist.
+    Finally, it's much easier to figure what local files are meant to
+    do because everything they contain is meaningful.
+
+  * Misc: Removed the start-up message stating that "this program is
+    derived from DEU 5.21 by Raphaël Quinet and Brendon Wyber" (for
+    clarity, not because I'm in denial).
+
+  * Platform: On DOS, the PPM files created by "make_palette_ppm" and
+    "mp2" now have correct CRLF line terminators instead of LFCR.
+
+  * Platform: Wart in gfx.cc to cope with QNX where DisplayWidth() and
+    DisplayHeight() return silly values.
+
+  * Platform: Added support for 16-colour displays. Tested with the
+    XFree86 VGA16 server which, when running in 640x480x16 (VGA mode
+    12h), provides a PseudoColor or StaticColor visual with an 8 bits
+    per pixel pixmap format. If there are any servers that expect a
+    pixmap format with a number of bits per pixel that is not a
+    multiple of 8, they're still unsupported.
+
+  * Platform: Reworked the pixmap format selection code. Should not
+    change anything for most people.
+
+  * Platform: Compiles and runs on HP-UX 10.0 (with GCC 3.0.1).
+
+  * Platform: Compiles on Linux PPC (with GCC 3.1). Thanks to Mark
+    Brown for the patch.
+
+Yadex 1.5.2 (2001-06-30)
+
+  * Platform: Compiles with GCC 3.0 (added std:: qualifiers where they
+    were missing and removed #ifdef inside printf()).
+
+Yadex 1.5.1 (2000-12-12)
+
+  * Platform: One-line fix in menu.cc to please GCC 2.96 (of Red Hat 7
+    fame). Thanks to Zebediah C. McClure for reporting the problem.
+
+Yadex 1.5.0 (2000-08-27)
+
+  * Build: Changed the way the diffs are generated after reading more
+    carefully the patch(1) man page and learning the hard way that it's
+    a very bad idea to put absolute paths in patches.
+
+  * Build: Made it easier to add or remove individual options in CFLAGS
+    and friends.
+
+  * Command-line: New option -b to benchmark parts of Yadex. For
+    hackers only.
+
+  * Command-line: Removed option -e in prevision of reuse for another
+    function.
+
+  * Doc: Completed ygd.html.
+
+  * Doc: Documented the usage of the LINES and YADEX_DIR environment
+    variables.
+
+  * Editing: Things that have an illegal angle are now shown with the
+    angle Doom would see, instead of just a dot in the middle. The
+    emulation is believed to be accurate for angles comprised between 0
+    and 359. Values outside that range have not been tested.
+
+  * Editing: Things flags and linedefs flags now grouped by 4 for
+    readability. For linedefs, the decimal value of the flags field is
+    not shown anymore.
+
+  * Editing: In the object info box, the type and description of the
+    current thing are now display in red if the type is invalid (i.e.
+    not defined in the .ygd).
+
+  * Editing: The things and linedefs flags operations ([a], [b], [c])
+    now set MadeChanges as they should have from the start.
+
+  * Editing: The View menu now contains entries for "Show object
+    numbers" [&] and "Show grid" [h].
+
+  * Editing: The Edit menu now contains entries for "Snap to grid" [y]
+    and "Loc grid step" [z].
+
+  * Editing: Rearranged the sidedef object info windows so that the
+    textures are listed in a more intuitive order (upper, middle, lower
+    instead of middle, upper, lower). Made labels shorter in
+    preparation of the hypothetical inclusion of texture swatches in
+    the future.
+
+  * Editing: Fixed long-standing buglet with the sidedef info saying
+    there are missing upper/lower textures even though both sectors
+    have a "sky" ceiling/floor.
+
+  * Editing: Implemented showing object numbers for linedefs and
+    sectors. The placement of sector numbers is naive and inadequate
+    for sectors that don't have a simple convex shape, but it's still
+    better than nothing. Picked a somewhat brighter colour for object
+    numbers.
+
+  * Editing: Linedef object info box: if the first sidedef is missing,
+    the message "(no first sidedef)" is printed in red instead of dim
+    gray. Same thing for the second sidedef if the "2" flag is set.
+
+  * Editing: Removed careless dereferencing of SideDefs[] for bad
+    sidedef numbers in the sector selection code. I don't think this is
+    what caused the mysterious unreproducible segfault James Caldwell
+    reported, though. Made the object deletion function paranoid
+    (checks that the objects to delete actually exist).
+
+  * Editing: When found superimposed linedefs after merging vertices,
+    the dialog box that asks whether they should be merged now mentions
+    the numbers of the first two superimposed linedefs found instead of
+    a laconic "Some linedefs are superimposed".
+
+  * Editing: Zooming: the zoom factor is now displayed in percent, 100%
+    being 1/1.
+
+  * Editing: Zooming: the zoom factors are now regularly spaced, with a
+    ratio of 1.414 between them. This removes the annoying "jump"
+    between the zoom factors greater than 1/2. It also fixes the
+    oddities that happened when zooming in after [`]. The ratio between
+    zoom factors can be controlled through the new parameter
+    "zoom_step".
+
+  * Editing: Zooming: the "zoom" parameter has been replaced by the new
+    parameter "zoom_default". The latter is expressed in percent, not
+    in 1/n units. It's now possible to specify an initial zoom factor
+    of more than 1/1. When opening a new window, Yadex now adjusts the
+    zoom factor so that the level fills the window. Should you want to
+    revert to the old behaviour, you can do it by setting zoom_default
+    to 12.
+
+  * Editing: ['] and [`] now go to the current centre of the level
+    (they used to go to where the centre was when the level was opened
+    or created).
+
+  * Editing: [`] now has a menu item (View -> Whole level).
+
+  * Editing: The grid has changed. There are now dots every step map
+    units, dim lines every 4×step units, normal lines every 16×step
+    units and bold lines every 64×step units. The new grid is supposed
+    to be less obtrusive visually, faster to display and more distinct
+    when scrolling.
+
+  * Editing: New function to swap floor and ceiling flats of selected
+    sectors (Misc. operations -> Swap flats).
+
+  * Editing: When not in things mode, things are drawn in a dimmer
+    shade of gray and do not hide the linedefs anymore.
+
+  * Game/wad: Removed the "-g wolf" bit. [For those who still haven't
+    got it : the support for Wolfenstein 3D announced in the CHANGES
+    for version 1.4.0 was of course a hoax, 1.4.0 having been released
+    on April 1st.] Hope you've been having as much fun as I have. :-)
+
+  * Game/wad: Heretic: made the golem leader ghost, undead warrior
+    ghost and golem ghost look a little more ghostly. Made the gargoyle
+    leader, golem leader and golem leader ghost look different from
+    their vanilla counterparts by using sprites IMPXD and MUMMY.
+    Assigned a sprite to things 31 and 32 (enchanted shield, SHD2 and
+    mystic urn, SPHL).
+
+  * Game/wad: Heretic: corrected things radii in heretic.ygd, using
+    info2ygd and the Heretic source as a reference. Almost all radii
+    were wrong, a few grossly so (maulotaur, ironlich and gargoyle).
+
+  * Game/wad: Strife: many new things and linedef types thanks to Matt
+    Miller.
+
+  * Game/wad: Doom alpha 0.4: definitions for thing types 2020, 2036,
+    2038 and 2046.
+
+  * Game/wad: Updated format comments in *.ygd.
+
+  * Game/wad: Sprites in pwads now supported (between S_START/S_END or
+    SS_START/SS_END or SS_START/S_END). This fixes Yadex's failure to
+    show redefined sprites in alitcsf.wad, basilica.wad and
+    strifed1.wad. A few Aliens TC sprites don't work yet but it's for a
+    different reason (DEH).
+
+  * Game/wad: Sprites now shown on the map when in things mode. You can
+    switch between sprites and squares with View -> Show sprites [%].
+    New config file parameter "sprite_scale" to adjust the scale at
+    which sprites are displayed (default 100%).
+
+  * Game/wad: The right sprite is shown, even if the sprites are not in
+    alphabetical order in the wad (cf BARWA0 in Strife).
+
+  * Game/wad: The function to add pwads (be it from the command line or
+    with the "r" command) has been heavily reworked. It's more robust
+    and handles errors better. It does not leak file handles anymore
+    when you add the same pwad more than once. It also accepts to add
+    iwads, modulo a warning (though you should expect problems later if
+    you do that). The merging of the pwad directory into the master
+    directory is still lousy.
+
+  * Game/wad: Fixed duplicate entries in the flat selector. This bug
+    was found by "Ras2". It happened whenever you added the same flat
+    thrice or more.
+
+  * Game/wad: EDGE: added definitions for EDGE linedef types and things
+    types to doom.ygd and doom2.ygd. Thanks to Andrew Apted for
+    providing the ygd data.
+
+  * Game/wad: EDGE: in sector mode, show information for EDGE
+    extrafloors if there are any.
+
+  * Misc: A couple of calls to fatal_error() were turned into calls to
+    report_error() (don't abort).
+
+  * Misc: New game definition file directive "sky_flat" to specify the
+    name of the "sky" flat. Replaced all occurrences of F_SKY1 by
+    references to this parameter. Fixes Check -> Check for missing
+    textures for Hexen and Strife. Bumped game definition file version#
+    to 4.
+
+  * Misc: Because it seems to disturb people (and for the pleasure of
+    proving Matt wrong), I've made the texture selector clip textures
+    to size. Since there's no scrolling/zooming system yet, I also
+    enlarged the viewing area from 256×128 to 512×256 to alleviate the
+    lossage on large textures.
+
+  * Misc: Removed the "Press Shift-F1 to save image to file" text in
+    the selector. It's been a no-op ever since 1.0, anyway.
+
+  * Misc: In the selectors, pressing [F1] prints the location of the
+    current item to stdout (file name and offset). Works with flats,
+    patches and sprites but not textures. It's there to help trace Ras'
+    bug.
+
+  * Misc: Made LoadPicture() nicer and safer. It gracefully bails out
+    if there are more than 20 errors on a single picture. It does not
+    make Yadex abort anymore on read errors in the header or column
+    offset table. I've done this by modifying wad_read_i16() and
+    wad_read_i32() so other functions might have been impacted.
+
+  * Misc: Config file: commented out most settings (this has no visible
+    effect since those settings were just reiterations of the default
+    values built into the executable). Also changed the initialization
+    code so that Yadex can run without a config file.
+
+  * Misc: Config file: unknown variables are ignored with a warning
+    instead of triggering a fatal error. The intent is to facilitate
+    sharing config files between versions.
+
+  * Misc: Config file: bumped version# to 3.
+
+  * Misc: Made Yadex use YADEX_GAME as documented and not Y_GAME.
+    Oops !
+
+  * Misc: New feature in the flat/picture/sprite selector to show where
+    the current image comes from (file name and file offset). For
+    debugging.
+
+  * Misc: The window size (width/height and -w/-h) can now be expressed
+    in percent of the screen size, by appending a "%" to the value. The
+    default size, instead of being 640×480 in the executable and 900×
+    600 in the config file is now 90%×90%. It's still possible to give
+    absolute width and heights, of course.
+
+  * Misc: No tantrum thrown if the game definition file contains no
+    thing directive.
+
+  * Misc: Removed the check for sector headroom being < 1024 in Checks
+    -> Check for missing textures. It was sometimes annoying and
+    inaccurate anyway.
+
+  * Platform: Images display correctly on packed 24-bit X servers (i.e.
+    bits_per_pixel actually is 24 and not 32). The scanline_pad member
+    of the ScreenFormat structure is now honoured (not that XFree86
+    seemed to mind much when it wasn't).
+
+  * Platform: Began to clean the code up to make porting less
+    difficult.
+
+  * Platform: Added patch to get Yadex to compile with GCC 2.7 (patch/
+    gcc-2.7.diff). GCC 2.7 is officially considered unsupported,
+    though. You're on your own.
+
+Yadex 1.4.0 (2000-04-01)
+
+  * Command-line: The parsing of the command line arguments is now
+    case-sensitive. Yes, that's right, it used to be case-insensitive.
+    I never knew. I just realized it by accident. DOS is not dead.
+
+  * Doc: The man page now has an "OPTIONS" section.
+
+  * Doc: Three new makefile targets, man, dvi and ps, for people who
+    hack the doc.
+
+  * Editing: Made object numbers slightly more legible in crowded
+    areas.
+
+  * Game/wad: Added support for Wolfenstein 3D (-g wolf).
+
+  * Misc: The code that parses the configuration file is smarter and
+    its error messages are more informative. Doesn't choke anymore on a
+    line containing just spaces or on comments not starting on
+    column 1. Thanks to "Ras2" for reporting the bug.
+
+  * Misc: New commands "viewtex" and "viewflat" so that you can browse
+    textures and flats without having to open a level. This is
+    primarily useful to me, for testing purposes.
+
+  * Misc: More sanitization : the parsing of the configuration file is
+    now case-sensitive when matching option names and values ("yes"/
+    "no", "true"/"false", "on"/"off").
+
+  * Misc: The flat/patch/sprite/texture viewer does not flicker
+    anymore, and is somewhat faster when viewing textures. The list of
+    names in the flat viewer has grown from 3 to 5 lines.
+
+  * Misc: The diffs are now in unified format (supposedly just as good
+    and IMHO clearer).
+
+Yadex 1.3.2 (2000-01-14)
+
+  * Build: Oops ! I had forgotten to set CC and CXX back to their
+    "sane" values before cutting the 1.3.1 tarball.
+
+  * Code: "make dist" now also generates a diff.
+
+Yadex 1.3.1 (2000-01-12)
+
+  * Build: Fix for "Ras2"'s compile error with g++ 2.7.2.3 :
+
+      c++ src/disppic.cc
+      In file included from /usr/include/g++-2.7/defalloc.h:24,
+                       from /usr/include/g++-2.7/map.h:21,
+                       from /usr/include/g++-2.7/map:6,
+                       from src/patchdir.h:35,
+                       from src/disppic.cc:33:
+      /usr/include/g++-2.7/algobase.h:47: macro `min' used with too many (3) args
+      /usr/include/g++-2.7/algobase.h:57: macro `max' used with too many (3) args
+      make: *** [obj/0/disppic.o] Error 1
+
+  * Build: Fix for HAVE_NANOSLEEP being always false. Thanks to "Ras2"
+    for pointing it out.
+
+Yadex 1.3.0 (2000-01-11)
+
+  * Build: The makefile now honours the dependencies in yadex.dep.
+
+  * Build: Support for FHS-compliant systems: "make install" now copies
+    the man pages into /usr/local/share/man/man6/ if /usr/local/share/
+    man/ exists. If not, it still uses /usr/local/man/man6/ (requested
+    by Joseph Carter).
+
+  * Build: Added "#include <stddef.h>" to fix compilation error on
+    wads.cc under Solaris.
+
+  * Build: Downgraded the makefile and scripts to use the old backquote
+    syntax for command substitution, because Oliver Kraus' reports
+    suggest that the Solaris sh does not understand the "$()" syntax.
+    Barfulation !
+
+  * Build: New makefile target showconf that shows the value of all the
+    important macros as well as the output of certain commands. If you
+    have trouble compiling Yadex, mail me the output of "make
+    showconf".
+
+  * Build: A bunch of little changes in the makefile to try to make
+    build problems on Solaris go away.
+
+  * Doc: Fixed several discrepancies in README.
+
+  * Game/wad: Support for the german edition of Doom II (as the iwad
+    has no MAP31 and MAP32, Yadex 1.1.0 and 1.2.0 used to say "this is
+    the shareware version of the game").
+
+  * Game/wad: Replacement patches in pwads are now supported, even if
+    between PP_START and PP_END. Fixes failure to see redefined
+    textures with mbfedit!.wad, alitcwad.wad and certainly many others.
+    Replacement patches in pwads not between P_START/P_END or PP_START/
+    PP_END are not recognized anymore. Many PNAMES errors that would
+    have made previous versions of Yadex abort now just make it print
+    warnings.
+
+  * Misc: Cleaned up the web page source and makefile. Added
+    documentation, should someone else take over maintainership. No
+    harm in dreaming.
+
+  * Misc: New command viewpat to browse through the patches.
+
+  * Misc: It's now possible to have several different versions of Yadex
+    installed simultaneously. Some paths have changed :
+      + $(PREFIX)/share/games/ is now $(PREFIX)/share/games/yadex/$
+        (VERSION)/
+      + $(PREFIX)/etc/yadex.cfg is now $(PREFIX)/etc/yadex/$(VERSION)/
+        yadex.cfg
+      + ~/yadex.cfg is now ~/.yadex/$(VERSION)/yadex.cfg
+      + $(PREFIX)/bin/yadex changed to $(PREFIX)/bin/yadex-$(VERSION)
+      + $(PREFIX)/bin/ybsp changed to $(PREFIX)/bin/ybsp-$(VERSION)
+      + $(PREFIX)/bin/yadex is now a symlink pointing to yadex-$
+        (VERSION)
+      + $(PREFIX)/bin/ybsp is now a symlink pointing to ybsp-$(VERSION)
+
+    The insertion of a yadex/ component in the paths was done for two
+    reasons. In the first place, it was requested by Joseph Carter for
+    game definition files, to reduce clutter in $(PREFIX)/share/games/.
+    I extended it to configuration files because it I thought it was a
+    nice way not to clutter $(PREFIX)/etc/. On the other hand, it was
+    not done for man pages and executables because it would have
+    interfered.
+
+  * Misc: Fixed bug where if you typed "yadex: c level", then created
+    or edited a level and then closed the editing window, you got a
+    dozen of messages like this one : "Warning: error freeing colour
+    00005820h (BadAccess (attempt to access private resource denied))".
+    I hope this fixes the related item in TODO.
+
+Yadex 1.2.0 (1999-11-23)
+
+  * BSP: Added missing newline in banner.
+
+  * BSP: Silenced GCC 2.95.2 warnings about implicit braces.
+
+  * Build: The makefile doesn't rebuild doc/ every time a source file
+    is changed anymore.
+
+  * Build: Can now be built on machines where Perl is not installed.
+
+  * Build: The doc can now be built on machines with a non-GNU find.
+
+  * Build: Fixed compilation errors with GCC 2.95.2 in src/infobar.cc.
+
+  * Build: Silenced most GCC warnings.
+
+  * Code: Fixed a typo in the legal notices at the beginning of the
+    source files.
+
+  * Doc: HISTORY renamed as CHANGES, since that seems to be a more
+    widespread convention.
+
+  * Editing: The checks don't beep for every error anymore, just the
+    first one.
+
+  * Editing: Object info window: the sprite and flats graphics don't
+    flicker anymore when the pointer moves from one object to another.
+    Besides, if the sprite is not found, displays the message
+    "sprite_name not found" instead of just a blank area.
+
+  * Game/wad: Doom alpha & press release versions: it's now possible to
+    save levels. Note: they're saved to regular Doom format, not Doom
+    alpha format.
+
+  * Game/wad: Doom II: The boss shooter thing now has a sprite
+    (BOSFB0).
+
+  * Game/wad: Hacx and Aliens TC: fixed a bug that made Yadex segfault
+    when trying to edit a Hacx level (or alitcsf.wad from alntc19
+    {a,b}.zip).
+
+  * Game/wad: For homogeneity with DeuTex, less confusion and to reduce
+    the risk of conflicts with other applications, the game names for
+    Doom alpha 0.2, Doom alpha 0.4, and Doom alpha 0.5 are now
+    "doom02", "doom04" and "doom05" respectively instead of "alpha02",
+    "alpha04" and "alpha05". It follows that some command-line options
+    have changed :
+      + "-g alpha02" is now "-g doom02",
+      + "-g alpha04" is now "-g doom04",
+      + "-g alpha05" is now "-g doom05".
+
+    Configuration file directives :
+      + "game = alpha02" is now "game = doom02",
+      + "game = alpha04" is now "game = doom04",
+      + "game = alpha05" is now "game = doom05".
+
+    Paths :
+      + /usr/local/share/games/alpha02/ is now /usr/local/share/games/
+        doom02/,
+      + /usr/local/share/games/alpha04/ is now /usr/local/share/games/
+        doom04/,
+      + /usr/local/share/games/alpha05/ is now /usr/local/share/games/
+        doom05/,
+      + /usr/local/share/games/alpha02.ygd is now /usr/local/share/
+        games/doom02.ygd,
+      + /usr/local/share/games/alpha04.ygd is now /usr/local/share/
+        games/doom04.ygd,
+      + /usr/local/share/games/alpha05.ygd is now /usr/local/share/
+        games/doom05.ygd.
+
+  * Game/wad: Fixed Yadex aborting when trying to view textures for
+    versions of Strife >= 1.1. The problem was that Strife 1.1 and
+    above use a different format for the TEXTURE1 and TEXTURE2 lumps
+    (Strife 1.0 uses the same format as Doom). New game definition file
+    directive "texture_format strife11" to support that format.
+    strife.ygd now contains "texture_format strife11". Added
+    strife10.ygd that is identical to strife.ygd except that it
+    contains "texture_format normal". Summary :
+
+      + if you have the Strife 1.0 iwad, use "-g strife10" or "game =
+        strife10",
+      + if you have Strife 1.1 or above, use "-g strife" or "game =
+        strife".
+
+    Thanks to Kim Parrott for reporting the bug and Len Pitre for
+    pointing me in the right direction.
+
+  * Misc: The "dump" command now prints correctly the last line even if
+    the length of the lump is not a multiple of 16.
+
+  * Misc: For homogeneity with DeuTex, the following game definition
+    file directives have changed :
+      + "texture_format alpha04" is now "texture_format nameless",
+      + "texture_lump texture1" is now "texture_lump normal",
+      + new choice "texture_lump none".
+
+  * Misc: For homogeneity with DeuTex, automatic texture names for Doom
+    alpha 0.4 are now "TEXnnnn" where nnnn is zero-based.
+
+  * Misc: Bumped game definition file version# to 3.
+
+  * Misc: When trying to use a pwad as iwad, emit a warning instead of
+    seeing this as a fatal error.
+
+  * Misc: Added a palette viewer (PLAYPAL and COLORMAP). Can be run
+    from the prompt with the viewpal command or from the level editing
+    window with [Ctrl][P].
+
+  * Misc: The sometimes tedious pwad loading messages are not displayed
+    anymore, unless in verbose mode. By default, Yadex now just prints
+    which levels the pwad contains.
+
+Yadex 1.1.0 (1999-08-22)
+
+  * BSP: Included Colin Phipps' fix for the bugs in bsp23bug.zip.
+
+  * BSP: Renamed the executable and the man page as ybsp, to avoid
+    having Yadex and Xwadtools overwrite each other's BSP.
+
+  * BSP: The whirling baton is now disabled if stderr is not a TTY.
+    This is the same thing Udo Munk did for Xwadtools' BSP with the
+    -noprog option except that here it's automatic.
+
+  * BSP: Made the man page spell out exactly which version of BSP this
+    is.
+
+  * BSP: Inserted notice in the banner that this is the version that
+    comes with Yadex. In the online help, replaced "TMP.WAD" by the
+    correct "tmp.wad".
+
+  * Building: Fixed compilation error on line 44 of bitvec.h.
+
+  * Code: Removed CR characters that remained in some of the source
+    files.
+
+  * Code: New function DrawScreenString(). Began to use it instead of
+    DrawScreenText(). This should squash some latent bugs, for example
+    regarding flat and texture names containing percent signs (%).
+
+  * Code: Fixed constness warnings in cfgfile.cc.
+
+  * Code: Replaced most occurrences of hard-coded 8 by one of WAD_NAME,
+    WAD_FLAT_NAME, WAD_PIC_NAME and WAD_TEX_NAME.
+
+  * Code: New directives level_format and level_name in the YGD files.
+    As a result, been able to remove most tests on specific values of
+    the game parameter.
+
+  * Doc: Too many changes and additions to list. Since the last
+    release, the HTML doc has doubled in size (from 80 kB to 160 kB).
+    Added a dozen of screenshots.
+
+  * Doc: In an attempt to make it easier to find what you're looking
+    for, I've split the doc in a larger number of files, referred to by
+    a top level index.html.
+
+  * Doc: Moved the HTML doc and the man pages to the doc/ directory, so
+    as not to clutter the base directory too much.
+
+  * Doc: Man pages: the first argument of the .TH macro (the name) is
+    now all caps since that's what (almost) everybody else does.
+
+  * Editing: Autoscroll is now off by default -- use "autoscroll =
+    true" in yadex.cfg if you want it back.
+
+  * Editing: New bindings [e] and [Ctrl][e] to select all linedefs that
+    belong to the same non-forked path.
+
+  * Editing: New bindings [E] and [Ctrl][Shift][e] to select all
+    single-sided linedefs that belong to the same non-forked path.
+
+  * Editing: New functions to flip and mirror linedefs, sectors, things
+    and vertices.
+
+  * Editing: Fixed the "string art" bug. That was a subtle bug that
+    happened only as a result of a rare chain of events. The recipe to
+    it is to render a vertex unused (for example by deleting all the
+    linedefs that use it), save the level, make a change that does not
+    call for a rebuilding of the nodes (for example, moving a thing or
+    changing an attribute of a sector), save the level, quit and load
+    again. At that point, a nice surprise awaits you: the linedefs are
+    all entangled (hence the name). Spectacular, and even beautiful,
+    but also very annoying if you don't have a backup copy of your
+    level.
+
+    This is the same bug I thought I had fixed in Yadex 1.0.0_alpha3.
+    In fact, I had cut one of the paths that led to it but the bug
+    itself was still there. It reappeared in february 1999.
+
+  * Editing: Fixed an old DEU bug where you sometimes couldn't select a
+    newly created sector to the west of the level until you saved.
+
+  * Editing: It's now possible to toggle linedef flags 8-15 and to
+    specify linedef flags field values greater than 511.
+
+  * Editing: It's now possible to set/clear/toggle things flags 7-15.
+
+  * Editing: Made the Not-enough-player-starts and
+    Not-enough-deathmatch-start dialogs on saving more intuitive (it
+    was about time).
+
+  * Editing: New function "Exchange objects numbers".
+
+  * Editing: Things types are now displayed in decimal, not in
+    hexadecimal. Other minor cosmetic changes.
+
+  * Editing: The focus-on-object function now works much better. It
+    does not land off-target or zoom in excessively anymore.
+    Superimposed things and sectors containing other sectors or not
+    containing their own centre don't confuse it anymore. It's still
+    fooled by unclosed sectors, though.
+
+  * Editing: Changed the meaning of [q]. It used to save and quit. Now
+    it just quits (same thing as [Esc]).
+
+  * Editing: The edit command can now edit levels of any name. If you
+    had a wad with a level named "FOO" in it, you could edit that level
+    by typing "edit foo". In case you're wondering, no there's no
+    practical application to this (beyond experimenting).
+
+  * Editing: Reminder to build nodes: the message is now more specific.
+
+  * Editing: Command mode: typing ^D at the prompt now works.
+
+  * Editing: Insert linedef and split sector: the new linedef now goes
+    from the first selected vertex to the second and not the other way
+    around.
+
+  * Editing: Insert linedef and split sector: does not loop forever
+    anymore if there are forks in the edge of the sector (for example
+    like when trying to split between vertices 283 and 278 of MAP01 of
+    Doom II).
+
+  * Editing: [n], [p], [>] and [<] now move the view so that the object
+    to highlight is under the pointer.
+
+  * Editing: The messages displayed when loading pwads are more compact
+    (several lumps are printed on the same line and groups of sprites
+    are collapsed). The end marker for groups of flats, patches and
+    sprites is now printed.
+
+  * Editing: Flat/sprite/texture viewer : added bindings [Ctrl][u] and
+    [Ctrl][w] to erase to start of line, [Ctrl][f] and [Ctrl][v] to
+    page down and [Ctrl][b] to page up.
+
+  * Editing: Flat/sprite/texture viewer : added bindings [Ctrl][PgUp]
+    and [Ctrl][PgDn] to move to top and bottom of list, because [Home]
+    and [End] will eventually cease to be available for that (they will
+    be bound to SOL and EOL).
+
+  * Editing: Flat/sprite/texture viewer : made [Up] and [Down] work
+    even when there are duplicate names.
+
+  * Editing: Flat/sprite/texture viewer : InputNameFromListWithFunc()
+    is now genuinely case insensitive. The positioning in the list of
+    names is now correct, even if the name given is lower-case.
+
+  * Editing: Flat/sprite/texture viewer : reduced flickering (still
+    room for improvement, though).
+
+  * Editing: Flat/sprite/texture viewer : the current name was way too
+    dim if not in the list. Fixed.
+
+  * Editing: Flat/sprite/texture viewer : made image window 320x200
+    instead of 256x128.
+
+  * Editing: Sprite viewer : new bindings [Ctrl][n] and [Ctrl][p] to go
+    to start of next/previous group of sprites.
+
+  * Editing: Sprite viewer : fixed display bug.
+
+  * Editing: Spectres now look more like spectres.
+
+  * Editing: Confirm-or-cancel dialogs: more intuitive. You can now
+    confirm with [y] or [Return] and cancel with [n] or [Esc]. All
+    other keys are ignored (previously, [y] confirmed and all other
+    keys cancelled). Expose events are now handled (previously they
+    were ignored).
+
+  * Editing: Some abnormal conditions that used to trigger fatal errors
+    now just cause a message error to be printed. The current operation
+    is aborted but not the whole program anymore.
+
+  * Game/wad: Fixed segfault on levels containing a thing of type 0
+    (like Eternal MAP25 and some Final Doom maps).
+
+  * Game/wad: When reading a level from a wad, now verifies that the
+    SECTORS, THINGS, VERTEXES, LINEDEFS and SIDEDEFS lumps have correct
+    sizes and that sidedefs, sectors and vertices references are
+    correct.
+
+  * Game/wad: Final Doom : should be supported now. Yadex does not
+    assume anymore that F1_START is always present, which caused it to
+    segfault on either or both Final Doom iwads.
+
+  * Game/wad: Heretic : added sprite names for 58 thing types.
+
+  * Game/wad: Hexen : added very partial support (-g hexen). You can
+    edit levels but not save them. Hexen-specific linedef and things
+    fields are ignored, and so is the BEHAVIOR lump. Most definitions
+    are missing.
+
+  * Game/wad: Strife : added partial support (-g strife). Yadex now
+    knows about the translucent linedef flag and the new sector types.
+    Thanks to Len Pitre for the help. Still missing : the new things
+    flags, most things types and linedefs types. Anybody wants to work
+    on strife.ygd ?
+
+  * Game/wad: MBF : supported. Yadex now knows about the friendly thing
+    flag, thing type 888 (Dog) and linedef types 271 and 272 (transfer
+    sky texture).
+
+  * Game/wad: Doom press release pre-beta : supported (-g doompr).
+    Added support for the PR picture format and the definitions for
+    things 2016 (evil sceptre) and 2017 (unholy bible).
+
+  * Game/wad: Doom alpha : read-only support (-g alpha02|alpha04|
+    alpha05). Added support for the alpha picture format, the TEXTURES
+    lump, the different level format and the incompatible level names
+    (E1M10 through E1M13).
+
+  * Game/wad: Added support for FF_START/FF_END in addition of FF_START
+    /F_END. As a result, Yadex does not barf anymore on basilica.wad
+    (but issue a warning). F?_START is not supported anymore ; it has
+    to be FF_START.
+
+  * Game/wad: Made "Post too long. Wad file might be corrupt" a
+    warning, not a fatal error anymore.
+
+  * Game/wad: New directives picture_format, texture_format and
+    texture_lump in the YGD files, to support Doom alpha and Doom PR.
+
+  * Misc: New command make_palette_ppm to generate a raw PPM file
+    containing all the colours of the palette.
+
+  * Misc: Cosmetic changes in the prompt and character mode interface.
+
+  * Misc: make_gimp_palette : the generated palette files now include
+    RGB values in the comments.
+
+  * Misc: Removed from the menus the functions that were not
+    implemented (File->Print, Edit->Find, View->3D preview).
+
+  * Misc: Failure to load the specified X font is not a fatal error
+    anymore.
+
+  * Misc: New command line options --help and --version.
+
+  * Misc: Bumped game definition file version# to 2.
+
+  * Platform: Removed dependency on nanosleep(), strcasecmp() and
+    strncasecmp(). Thanks to Udo Munk for pointing out that nanosleep()
+    is not always available.
+
+  * Platform: Now compiles with other compilers than GCC/EGCS without
+    modifying the makefile.
+
+  * Platform: New parameter idle_sleep_ms to set the time in ms between
+    polls of the X server when the input queue is empty.
+
+  * Platform: Previously, if the CPU and the X server had different
+    endiannesses and the screen depth was more than 8 bits, sprites,
+    flats and textures were displayed with wrong colours. This is now
+    fixed.
+
+  * Platform: The build, group, insert and save commands should now
+    work correctly on big-endian machines.
+
+  * Platform: The bell has been resurrected on X.
+
+  * Platform: Should now compile on X11R5 systems (to be verified).
+    Thanks to Udo Munk for the fix.
+
+Yadex 1.0.1 (1999-01-02)
+
+  * Doc: New sections "Moving around" and "Other credits" in the user's
+    guide.
+
+  * Editing: Split linedefs and sector: new linedef now goes from 1 to
+    2 and not the other way around.
+
+  * Editing: Added scrolling with the arrow keys.
+
+  * Editing: [Pgup], [Pgdn], [Home] and [End] now scroll one page at a
+    time.
+
+  * Editing: New variable autoscroll to disable autoscrolling.
+
+  * Editing: New variables autoscroll_amp and autoscroll_edge to tweak
+    autoscrolling.
+
+  * Editing: New shortcut [x] to "Split linedef (insert new vertex)".
+
+  * Editing: New shortcut [w] to "Split linedefs and sector".
+
+  * Misc: Fixed segfault on trying to edit MAPnm in Doom/Heretic mode
+    or EnMm in Doom II mode.
+
+  * Misc: New prompt command make_gimp_palette to generate a gimp
+    palette file from PLAYPAL.
+
+  * Misc: Bumped configuration file version# to 2.
+
+Yadex 1.0.0 (1998-12-26)
+
+  * Code: Moved the source files to a subdirectory.
+
+  * Doc: A few additions in the user's guide
+
+  * Editing: Fixed buglet in positioning of newly copied objects.
+
+  * Game/wad: Game support: added definitions for Boom's things 5001
+    and 5002 (point pusher and puller).
+
+  * Misc: Added reminder to build nodes after making changes.
+
+  * Misc: Added magic string to configuration file.
+
+  * Misc: Added magic string to game definition file.
+
+Yadex 1.0.0_alpha3 (1998-12-23)
+
+  * Doc: A few additions/corrections in the hacker's guide.
+
+  * Editing: Fixed spectacular corruption of linedefs (string art bug)
+    that occurred if all you did during a given session was deleting
+    vertices.
+
+Yadex 1.0.0_alpha2 (1998-12-22)
+
+  * BSP: Included BSP 2.3 (thanks to Lee Killough).
+
+  * Doc: Improved user's guide.
+
+  * Editing: Added new commands [a], [b] and [c] to set, toggle and
+    clear things and linedefs flags.
+
+Yadex 1.0.0_alpha1 (1998-12-17)
+
+  * Code: Removed dereferencing of NULL pointer in
+    ParseCommandLineOptions() (DEU).
+
+  * Code: Replaced occurrences of "x==TRUE" and "x==FALSE" by "x" and
+    "!x".
+
+  * Code: Replaced occurrences of "x=TRUE" and "x=FALSE" by "x=1" and
+    "x=0".
+
+  * Command-line: You don't have anymore to put "-file" or "-pwad" in
+    front of pwads names on the command line. E.G. you can type "yadex
+    foo.wad".
+
+  * Command-line: Deleted a few little-used or DOS-specific options.
+
+  * Editing: Menu bar and pop-up menus much improved.
+
+  * Editing: Info bar reworked.
+
+  * Editing: When prompted to "Press a key to continue", you can now
+    also press the left mouse button.
+
+  * Editing: Grid: the grid step can now adapt automatically as you
+    zoom in/out.
+
+  * Editing: Grid: whether dragging is snapped to grid is now
+    independent of whether the grid is shown or not (added flags
+    grid_snap and grid_shown).
+
+  * Editing: Added finer-grained confirmation options.
+
+  * Editing: General editing: you can now scroll the map further from
+    the centre of the level.
+
+  * Editing: Added ['] to re-centre the window around the centre of the
+    map.
+
+  * Editing: Added [`] to re-centre the window around the centre of the
+    map and adjust the zoom so that the map fills the screen.
+
+  * Editing: Added [&] to show things and vertices numbers.
+
+  * Editing: Autoscroll: scroll speed is now progressive.
+
+  * Editing: Autoscroll: easier to use near the top of the window.
+
+  * Editing: [Left], [Right], [Up], [Down] do nothing.
+
+  * Editing: [Space] does not toggle move fast/slow anymore; it toggles
+    between nominal zoom and x 4.
+
+  * Editing: Highlighting of things, vertices and linedefs much
+    improved.
+
+  * Editing: Dragging objects is now done with the left mouse button
+    instead of the right button.
+
+  * Editing: Editing object properties is now done by double-clicking
+    on the object.
+
+  * Editing: Selection and drag-and-drop have changed a lot.
+
+  * Editing: Selection box: removed the -a option and the addselbox
+    parameter. Whether the selection box is additive or not is now
+    controlled dynamically by the user (with [Ctrl]).
+
+  * Editing: Sprite viewer: sprites are now centred.
+
+  * Editing: Linedef info: shortened flags names to one character.
+
+  * Editing: Linedef info: a missing normal texture on a 1-sided
+    linedef is now flagged in red.
+
+  * Editing: Linedefs copy: you now have the choice between duplicating
+    the sidedefs too and reusing the same sidedefs. DEU left the new
+    linedefs sidedef-less and, so far, Yadex used to reuse the same
+    sidedefs.
+
+  * Editing: Linedefs: added function to "unlink" sidedefs.
+
+  * Editing: Linedefs: dragging linedefs is much faster than before.
+
+  * Editing: Sectors: in the object info window, added display of floor
+    and ceiling height delta with respect to previous sector.
+
+  * Editing: Sectors: in the object info window, added display of floor
+    and ceiling texture.
+
+  * Editing: Sectors: dragging sectors is much faster than before.
+
+  * Editing: Things: now drawn as squares so that it's easier to see
+    whether they are stuck in a wall or another thing. And you don't
+    have to highlight them to see their angle. Note: the old shape is
+    still available by defining ROUND_THINGS at compile-time.
+
+  * Editing: Things: changed the colours again. Tried to make important
+    things stand out and conversely. Bonuses are now dark green and
+    player/ deathmatch starts bright green. Keys are magenta.
+    Decoration is dim blue instead of white. Unknown objects are cyan
+    instead of white. Weapons are orange instead of brownish. Heretic
+    sound source things and Boom point pushers are dim turquoise-ish.
+
+  * Editing: Things: the sprite is now shown in the object info window.
+
+  * Editing: Vertices: deciding whether a vertex is on a linedef is now
+    done on the distance in pixels, not in map units. So you can now
+    work on very fine details (E.G. vertices only 2 map units away)
+    provided that the zoom factor is high enough.
+
+  * Editing: Fixed minor glitch in texture viewer that showed with
+    BIGDOOR7, SKY1, TEKWALL1, TEKWALL5 and others (DEU).
+
+  * Editing: When highlighting a sector, compared SideDefs[LineDef
+    [n].sidedef1].sector with ObjNum even though .sector was -1.
+    Somehow it always tested false (DEU).
+
+  * Editing: "Check textures names": the name of the offending texture
+    is now printed correctly even if it is 8 characters long (DEU).
+
+  * Editing: "Check textures names": if you fixed a missing texture,
+    the editor was not made aware that you had made changes to the
+    level (DEU).
+
+  * Editing: Unused sectors are not selected anymore (DEU).
+
+  * Editing: Changing the preferences could overwrite other variables
+    (DEU).
+
+  * Editing: InputNameFromListWithFunc() used to segfault if you
+    pressed [Pgdn] on a list shorter than (listdisp + 1) elements
+    (DEU).
+
+  * Editing: Removed segfault in AlignTexturesX() (DEU).
+
+  * Game/wad: Heretic is now supported.
+
+  * Game/wad: Added support for Boom's new thing flags
+    not-in-deathmatch and not-in-coop.
+
+  * Game/wad: Added support for Boom's new linedef flag pass-through.
+
+  * Misc: Renamed as Yadex to avoid confusion with Yet Another Diagram
+    Editor.
+
+  * Misc: Loading pwads: implemented standard directories. If the pwad
+    to load is in one of the standard directories (or a subdirectory)
+    you don't have to type the whole name.
+
+  * Misc: Loading pwads: added standard directories and made the
+    messages less verbose for pwads that contain patches (PP_START/
+    PP_END).
+
+  * Misc: Removed segfault during fatal_error() on failure to open the
+    iwad (DEU).
+
+  * Misc: The prompt now groks TTYs with a number of lines other than
+    25.
+
+  * Misc: Changed the welcome message (a.k.a. "reminder").
+
+  * Misc: Added an "About Yadex..." window.
+
+  * Misc: Don't copy SEGS, SSECTORS, NODES, REJECT and BLOCKMAP from
+    the original file anymore when the map has changed. Makes smaller
+    wad files. Nice for archival.
+
+  * Misc: Added environment variable YADEX_GAME.
+
+  * Platform: Ported to X (plain Xlib). This version is not available
+    for DOS.
+
+  * Platform: Now works on big-endian machines.
+
+  * Platform: Removed several DOS-isms from file name handling code.
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/COPYING	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,340 @@
+		    GNU GENERAL PUBLIC LICENSE
+		       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+                          59 Temple Place - Suite 330, Boston, MA
+                          02111-1307, USA.
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+		    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+			    NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+
+	Appendix: How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) 19yy  <name of author>
+
+    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.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) 19yy name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/COPYING.LIB	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,482 @@
+		  GNU LIBRARY GENERAL PUBLIC LICENSE
+		       Version 2, June 1991
+
+ Copyright (C) 1991 Free Software Foundation, Inc.
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the library GPL.  It is
+ numbered 2 because it goes with version 2 of the ordinary GPL.]
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+  This license, the Library General Public License, applies to some
+specially designated Free Software Foundation software, and to any
+other libraries whose authors decide to use it.  You can use it for
+your libraries, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if
+you distribute copies of the library, or if you modify it.
+
+  For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you.  You must make sure that they, too, receive or can get the source
+code.  If you link a program with the library, you must provide
+complete object files to the recipients so that they can relink them
+with the library, after making changes to the library and recompiling
+it.  And you must show them these terms so they know their rights.
+
+  Our method of protecting your rights has two steps: (1) copyright
+the library, and (2) offer you this license which gives you legal
+permission to copy, distribute and/or modify the library.
+
+  Also, for each distributor's protection, we want to make certain
+that everyone understands that there is no warranty for this free
+library.  If the library is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original
+version, so that any problems introduced by others will not reflect on
+the original authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that companies distributing free
+software will individually obtain patent licenses, thus in effect
+transforming the program into proprietary software.  To prevent this,
+we have made it clear that any patent must be licensed for everyone's
+free use or not licensed at all.
+
+  Most GNU software, including some libraries, is covered by the ordinary
+GNU General Public License, which was designed for utility programs.  This
+license, the GNU Library General Public License, applies to certain
+designated libraries.  This license is quite different from the ordinary
+one; be sure to read it in full, and don't assume that anything in it is
+the same as in the ordinary license.
+
+  The reason we have a separate public license for some libraries is that
+they blur the distinction we usually make between modifying or adding to a
+program and simply using it.  Linking a program with a library, without
+changing the library, is in some sense simply using the library, and is
+analogous to running a utility program or application program.  However, in
+a textual and legal sense, the linked executable is a combined work, a
+derivative of the original library, and the ordinary General Public License
+treats it as such.
+
+  Because of this blurred distinction, using the ordinary General
+Public License for libraries did not effectively promote software
+sharing, because most developers did not use the libraries.  We
+concluded that weaker conditions might promote sharing better.
+
+  However, unrestricted linking of non-free programs would deprive the
+users of those programs of all benefit from the free status of the
+libraries themselves.  This Library General Public License is intended to
+permit developers of non-free programs to use free libraries, while
+preserving your freedom as a user of such programs to change the free
+libraries that are incorporated in them.  (We have not seen how to achieve
+this as regards changes in header files, but we have achieved it as regards
+changes in the actual functions of the Library.)  The hope is that this
+will lead to faster development of free libraries.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.  Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library".  The
+former contains code derived from the library, while the latter only
+works together with the library.
+
+  Note that it is possible for a library to be covered by the ordinary
+General Public License rather than by this special one.
+
+		  GNU LIBRARY GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any software library which
+contains a notice placed by the copyright holder or other authorized
+party saying it may be distributed under the terms of this Library
+General Public License (also called "this License").  Each licensee is
+addressed as "you".
+
+  A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+  The "Library", below, refers to any such software library or work
+which has been distributed under these terms.  A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language.  (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+  "Source code" for a work means the preferred form of the work for
+making modifications to it.  For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+  Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it).  Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+  
+  1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+  You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+  2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) The modified work must itself be a software library.
+
+    b) You must cause the files modified to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    c) You must cause the whole of the work to be licensed at no
+    charge to all third parties under the terms of this License.
+
+    d) If a facility in the modified Library refers to a function or a
+    table of data to be supplied by an application program that uses
+    the facility, other than as an argument passed when the facility
+    is invoked, then you must make a good faith effort to ensure that,
+    in the event an application does not supply such function or
+    table, the facility still operates, and performs whatever part of
+    its purpose remains meaningful.
+
+    (For example, a function in a library to compute square roots has
+    a purpose that is entirely well-defined independent of the
+    application.  Therefore, Subsection 2d requires that any
+    application-supplied function or table used by this function must
+    be optional: if the application does not supply it, the square
+    root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library.  To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License.  (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.)  Do not make any other change in
+these notices.
+
+  Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+  This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+  4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+  If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library".  Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+  However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library".  The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+  When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library.  The
+threshold for this to be true is not precisely defined by law.
+
+  If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work.  (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+  Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+  6. As an exception to the Sections above, you may also compile or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+  You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License.  You must supply a copy of this License.  If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License.  Also, you must do one
+of these things:
+
+    a) Accompany the work with the complete corresponding
+    machine-readable source code for the Library including whatever
+    changes were used in the work (which must be distributed under
+    Sections 1 and 2 above); and, if the work is an executable linked
+    with the Library, with the complete machine-readable "work that
+    uses the Library", as object code and/or source code, so that the
+    user can modify the Library and then relink to produce a modified
+    executable containing the modified Library.  (It is understood
+    that the user who changes the contents of definitions files in the
+    Library will not necessarily be able to recompile the application
+    to use the modified definitions.)
+
+    b) Accompany the work with a written offer, valid for at
+    least three years, to give the same user the materials
+    specified in Subsection 6a, above, for a charge no more
+    than the cost of performing this distribution.
+
+    c) If distribution of the work is made by offering access to copy
+    from a designated place, offer equivalent access to copy the above
+    specified materials from the same place.
+
+    d) Verify that the user has already received a copy of these
+    materials or that you have already sent this user a copy.
+
+  For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it.  However, as a special exception,
+the source code distributed need not include anything that is normally
+distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+  It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system.  Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+  7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+    a) Accompany the combined library with a copy of the same work
+    based on the Library, uncombined with any other library
+    facilities.  This must be distributed under the terms of the
+    Sections above.
+
+    b) Give prominent notice with the combined library of the fact
+    that part of it is a work based on the Library, and explaining
+    where to find the accompanying uncombined form of the same work.
+
+  8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License.  Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License.  However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+  9. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Library or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+  10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded.  In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+  13. The Free Software Foundation may publish revised and/or new
+versions of the Library General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation.  If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+  14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission.  For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this.  Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+			    NO WARRANTY
+
+  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+
+     Appendix: How to Apply These Terms to Your New Libraries
+
+  If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change.  You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+  To apply these terms, attach the following notices to the library.  It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the library's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Library General Public
+    License as published by the Free Software Foundation; either
+    version 2 of the License, or (at your option) any later version.
+
+    This library 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
+    Library General Public License for more details.
+
+    You should have received a copy of the GNU Library General Public
+    License along with this library; if not, write to the Free
+    Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+    MA 02111-1307, USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+  <signature of Ty Coon>, 1 April 1990
+  Ty Coon, President of Vice
+
+That's all there is to it!
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/FAQ	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,181 @@
+                               Fancy logo
+                        Yadex 1.7.0 (2003-12-28)
+
+                               Yadex FAQ
+
+Compilation problems
+
+   During configure,
+   error: none of (gcc, c89, cc) work, is your PATH set right?
+
+           You need a C compiler to compile Yadex.
+
+           If you have one but it's not in the path, either fix $PATH
+           or pass the full pathname to the configure script with the
+           --cc flag (E.G. "./configure --cc /opt/sfw/bin/gcc").
+
+           If it's in the path but it's not called gcc or c89 or cc,
+           pass the name to the configure script with the --cc flag
+           (E.G. "./configure --cc icc").
+
+   During configure,
+   error: none of (g++, c++, cxx) work, is your PATH set right?
+
+           You need a C++ compiler to compile Yadex.
+
+           If you have one but it's not in the path, either fix $PATH
+           or pass the full pathname to the configure script with the
+           --cxx flag (E.G. "./configure --cxx /opt/sfw/bin/g++").
+
+           If it's in the path but it's not called g++ or c++ or cxx,
+           pass the name to the configure script with the --cxx flag
+           (E.G. "./configure --cxx icc").
+
+   X11/Xlib.h: No such file or directory
+
+           Are you sure you have the Xlib headers ? If not, install
+           them. If you already have them, then find out where they
+           are and change the "X11INCLUDEDIR =" line in GNUmakefile
+           accordingly.
+
+   The compiler chokes on the Xlib headers
+
+           This happens on Solaris 2.6 with GCC 2.95.2. Oliver Kraus
+           says that the solution is to add "-fpermissive" to
+           "CXXFLAGS =" in GNUmakefile.
+
+   /usr/X11R6/lib/libX11.so: undefined reference to `recv'
+   /usr/X11R6/lib/libX11.so: undefined reference to `connect'
+   /usr/X11R6/lib/libX11.so: undefined reference to `socket'
+   /usr/X11R6/lib/libX11.so: undefined reference to `setsockopt'
+   /usr/X11R6/lib/libX11.so: undefined reference to `shutdown'
+   /usr/X11R6/lib/libX11.so: undefined reference to `gethostbyname'
+   /usr/X11R6/lib/libX11.so: undefined reference to `getservbyname'
+   /usr/X11R6/lib/libX11.so: undefined reference to `getpeername'
+   /usr/X11R6/lib/libX11.so: undefined reference to `getsockname'
+
+           This happens with QNX 6 and other Unices. Add "-lsocket"
+           to "LDFLAGS =" in GNUmakefile.
+
+   Solaris: can't resolve gettimeofday()
+
+           In GNUmakefile, add "-lrt" after "-lX11".
+
+   Mac OS X:
+   al_adigits.o literal C string section (__TEXT,__cstring) does not
+   end with a '\0'
+
+           As far as I can see, the code in Yadex is legal C, and Mac
+           OS X's ld is incorrect in rejecting it. As a workaround,
+           change the size of al_adigits[] from 36 to 37 in
+           al_adigits.c and atclib.h. The real fix is to complain to
+           Apple for selling you a linker that won't link valid C
+           code.
+
+   GCC 3.0: Yadex 1.5.1 doesn't compile
+
+           Get Yadex 1.5.2 or later.
+
+   GCC 2.96: Yadex 1.5.0 doesn't compile
+
+           Get Yadex 1.5.1 or later.
+
+   EGCS 1.1.2 / SuSE 6.2:
+   no matching function for call to `menu_c::menu_c (...)'
+
+           Apparently, there is a bug in certain EGCS 1.1.2
+           installations that makes them choke on src/editloop.cc. I
+           know no workaround. I'd suggest that you try to get a fix
+           from your distributor or use another compiler. EGCS 1.0.3,
+           EGCS 1.1.1 and GCC 2.95.2 are known to work.
+
+   GCC 2.7: lots of compilation errors
+
+           GCC 2.7 is a very old compiler, it does not implement the
+           current C++ standard and I don't support it. If you must,
+           try applying patch/gcc-2.7.diff that's included in the
+           archive but don't complain to me if it doesn't work.
+
+   GCC:
+   warning: comparison between signed and unsigned
+
+           GCC is over-sensitive to signedness mismatches. Don't
+           worry, that won't prevent Yadex from working.
+
+   GCC: In sanity.cc,
+   warning: decimal integer constant is so large that it is unsigned
+
+           Weird as it may sound, the standard says that the lowest
+           value that a signed long can hold is -(2^31). GCC sticks
+           to the party line, never mind that you're on a platform
+           like i386 where LONG_MIN is -(2^31) - 1.
+
+           You can ignore this warning.
+
+   GCC: In sanity.cc,
+   warning: this decimal constant is unsigned only in ISO C90
+
+           This is a new avatar (as of GCC 3.3) of the previous
+           warning. Ignore it.
+
+   Yadex 1.3.1 doesn't compile
+
+           There's a thinko in the makefile. It's fixed in version
+           1.3.2.
+
+   Yadex 1.1.0 doesn't compile
+
+           In src/infobar.cc, lines 48 and 49, replace
+
+   const char infobar_c::FILE_NAME_UNSET[1];  // A special pointer value
+   const char infobar_c::LEVEL_NAME_UNSET[1];  // A special pointer value
+
+           by
+
+   const char infobar_c::FILE_NAME_UNSET[1] = { ' ' };
+   const char infobar_c::LEVEL_NAME_UNSET[1] = { ' ' };
+
+   Yadex 1.0.1 doesn't compile
+
+           In src/vector.h, delete line 44 ("return this;") and
+           compile again.
+
+Misc.
+
+   I don't have an iwad
+
+           You can download certain iwads for free ;
+
+              * Doom 1.8 shareware iwad
+              * Heretic shareware version
+              * Hexen demo
+              * Strife demo
+
+   What about a 3D preview ?
+
+           Andrew Apted has written an amazing patch that does
+           exactly that.
+
+   Yadex is slow, particularly when dragging objects
+
+           Yes. I plan to replace the current implementation (pixmap)
+           by drawing directly to the window. The difficulty lies in
+           making that without generating a lot of flicker. In the
+           meantime, try the -P option.
+
+   How many people use Yadex ?
+
+           I don't know for sure. Each new release gets a few hundred
+           downloads.
+
+   Why didn't you use <insert speaker's favourite toolkit> ?
+
+           I used plain Xlib and not a toolkit for several reasons.
+           Firstly, I wanted to learn Xlib. Secondly, I reckoned it
+           would be easier to translate the existing BGI calls to
+           Xlib than to some higher level toolkit. Thirdly, I feared
+           that depending on a toolkit would hurt portability.
+
+     --------------------------------------------------------------
+
+   AYM 2003-12-28
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/GNUmakefile	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,889 @@
+#
+#	Makefile for Yadex
+#	Copyright © André Majorel 1998-2003.
+#	AYM 1998-06-10
+#
+
+# ATTENTION : GNU MAKE IS REQUIRED ! This makefile uses pattern
+# rules, addprefix, addsuffix, etc. It's not named "GNUmakefile"
+# for nothing.
+
+########################################################################
+#
+#	Definitions that only hackers
+#	might want to change
+#
+########################################################################
+
+# The name of the directory where objects and
+# binaries are put. I include the output of
+# "uname -a" to make it easier for me to build
+# Yadex for different platforms from the same
+# source tree.
+SYSTEM := $(shell echo `uname -n`_`uname -a | cksum` | tr -dc '[:alnum:]._-')
+OBJDIR             = obj/0
+DOBJDIR            = dobj/0
+OBJPHYSDIR         = obj/$(SYSTEM)
+DOBJPHYSDIR        = dobj/$(SYSTEM)
+OBJDIR_ATCLIB      = $(OBJDIR)/atclib
+DOBJDIR_ATCLIB     = $(DOBJDIR)/atclib
+OBJPHYSDIR_ATCLIB  = $(OBJPHYSDIR)/atclib
+DOBJPHYSDIR_ATCLIB = $(DOBJPHYSDIR)/atclib
+
+# Create all directories and make symlinks to
+# config.cc and config.h. Doing it at the start
+# makes things much simpler later on.
+DUMMY := $(shell							\
+	mkdir -p $(OBJPHYSDIR)  $(OBJPHYSDIR_ATCLIB);			\
+	mkdir -p $(DOBJPHYSDIR) $(DOBJPHYSDIR_ATCLIB);			\
+	[ ! -h $(OBJDIR)  ] || rm $(OBJDIR);				\
+	[ ! -h $(DOBJDIR) ] || rm $(DOBJDIR);				\
+	ln -s $(SYSTEM) $(OBJDIR);					\
+	ln -s $(SYSTEM) $(DOBJDIR);					\
+	)
+
+include $(OBJDIR)/Makefile.config
+
+########################################################################
+#
+#	Definitions that end users
+#	might want to change
+#
+########################################################################
+
+# Which OS ?
+OS := $(shell uname -s | tr A-Z a-z)
+
+# Where your X11 libraries and headers reside.
+# Current rule:
+# - AIX has them in /usr/lpp/X11/{lib,include},
+# - Solaris has them in /usr/openwin/{lib,include},
+# - all other unices in /usr/X11R6/{lib,include}.
+ifeq ($(findstring $(OS), aix), $(OS))
+  X11LIBDIR     = /usr/lpp/X11/lib
+  X11INCLUDEDIR = /usr/lpp/X11/include
+else
+  ifeq ($(findstring $(OS), solaris sunos), $(OS))
+    X11LIBDIR     = /usr/openwin/lib
+    X11INCLUDEDIR = /usr/openwin/include
+  else
+    X11LIBDIR     = /usr/X11R6/lib
+    X11INCLUDEDIR = /usr/X11R6/include
+  endif
+endif
+
+# $(CC) and $(CXX) are the C and C++ compiler respectively. They're
+# normally autodetected by ./configure and passed to make through
+# obj/0/Makefile.config.
+#CC  =
+#CXX =
+
+# Options used when compiling Atclib.
+CFLAGS = -O
+
+# Options used when compiling and linking Yadex.
+# ld is invoked through the C++ compiler so
+# LDFLAGS should not contain options that mean
+# something to the C++ compiler.
+CXXFLAGS = -O
+#CXXFLAGS += -DWHITE_BACKGROUND
+#LDFLAGS  =
+
+# Options used to compile and link the debugging
+# targets. Not used by normal end-user targets.
+# Unlike CFLAGS, CXXFLAGS and LDFLAGS, assume
+# GCC/EGCS.
+DCFLAGS		= -g -O
+DCFLAGS		+= -Wall			# GCC warnings
+DCFLAGS		+= -pedantic			# GCC warnings
+DCFLAGS		+= -Wno-parentheses		# GCC warnings
+DCFLAGS		+= -Wpointer-arith		# GCC warnings
+DCFLAGS		+= -Wcast-qual			# GCC warnings
+DCFLAGS		+= -Wcast-align			# GCC warnings
+DCFLAGS		+= -Wwrite-strings		# GCC warnings
+DCFLAGS		+= -Wmissing-declarations	# GCC warnings
+DCFLAGS		+= -Wmissing-prototypes		# GCC warnings
+DCFLAGS		+= -Winline			# GCC warnings
+DCFLAGS		+= -pg				# Profiling
+
+DCXXFLAGS	= -g -O
+DCXXFLAGS	+= -Wall			# GCC warnings
+DCXXFLAGS	+= -pedantic			# GCC warnings
+DCXXFLAGS	+= -Wno-parentheses		# GCC warnings
+DCXXFLAGS	+= -Wpointer-arith		# GCC warnings
+DCXXFLAGS	+= -Wcast-qual			# GCC warnings
+DCXXFLAGS	+= -Wcast-align			# GCC warnings
+DCXXFLAGS	+= -Wwrite-strings		# GCC warnings
+DCXXFLAGS	+= -Wmissing-declarations	# GCC warnings
+DCXXFLAGS	+= -Wmissing-prototypes		# GCC warnings
+#DCXXFLAGS	+= -Winline			# GCC warnings
+DCXXFLAGS	+= -pg				# Profiling
+
+DLDFLAGS	=
+DLDFLAGS	+= -pg				# Profiling
+#DLDFLAGS	+= -lefence			# Electric Fence
+
+
+########################################################################
+#
+#	Definitions that only hackers
+#	might want to change
+#
+########################################################################
+
+MAKEFILE = GNUmakefile
+VERSION := $(shell cat VERSION)
+VERPREV := $(shell test -f VERPREV && cat VERPREV)
+
+# All the modules of Yadex without path or extension.
+MODULES_YADEX =								\
+	acolours	aym		bench		bitvec		\
+	cfgfile		checks		colour1		colour2		\
+	colour3		colour4		config		credits		\
+	dependcy	dialog		disppic		drawmap		\
+	edisplay	editgrid	editlev		editloop	\
+	editobj		editsave	endian		editzoom	\
+	entry		entry2		events		flats		\
+	game		gcolour1	gcolour2	gcolour3	\
+	geom		gfx		gfx2		gfx3		\
+	gotoobj		help1		help2		highlt		\
+	img		imgscale	imgspect	infobar		\
+	input		l_align		l_centre	l_flags		\
+	l_misc		l_prop		l_unlink	l_vertices	\
+	levels		lists		locate		lumpdir		\
+	macro		memory		menubar		menu		\
+	mkpalette	mouse		names		nop		\
+	objects		objinfo		oldmenus	palview		\
+	patchdir	pic2img		prefer		s_centre	\
+	s_door		s_lift		s_linedefs	s_merge		\
+	s_misc		s_prop		s_slice		s_split		\
+	s_swapf		s_vertices	sanity		scrnshot	\
+	selbox		selectn		selpath		selrect		\
+	serialnum	spritdir	sticker		swapmem		\
+	t_centre	t_flags		t_prop		t_spin		\
+	textures	things		trace		v_centre	\
+	v_merge		v_polyg		vectext		verbmsg		\
+	version		wadfile		wadlist		wadnamec	\
+	wadres		wads		wads2		warn		\
+	windim		x_centre	x_exchng	x_hover		\
+	x_mirror	x_rotate	x11		xref		\
+	yadex		ytime
+
+# All the modules of Atclib without path or extension.
+MODULES_ATCLIB =							\
+	al_adigits	al_aerrno	al_astrerror	al_fana		\
+	al_fnature	al_lateol	al_lcount	al_lcreate	\
+	al_ldelete	al_ldiscard	al_lgetpos	al_linsert	\
+	al_linsertl	al_llength	al_lpeek	al_lpeekl	\
+	al_lpoke	al_lpokel	al_lptr		al_lread	\
+	al_lreadl	al_lrewind	al_lseek	al_lsetpos	\
+	al_lstep	al_ltell	al_lwrite	al_lwritel	\
+	al_sapc		al_saps		al_scps		al_scpslower	\
+	al_sdup		al_sisnum	al_strolc
+
+# The source files of Yadex and Atclib
+SRC_YADEX  = $(addprefix src/,     $(addsuffix .cc, $(MODULES_YADEX)))
+SRC_ATCLIB = $(addprefix atclib/,  $(addsuffix .c,  $(MODULES_ATCLIB)))
+
+# The headers of Yadex and Atclib
+HEADERS_YADEX  := $(wildcard src/*.h)
+HEADERS_ATCLIB =  atclib/atclib.h
+
+# All the source files, including the headers.
+SRC = $(filter-out src/config.cc, $(SRC_YADEX))				\
+      $(filter-out src/config.h, $(HEADERS_YADEX))			\
+      $(SRC_ATCLIB) $(HEADERS_ATCLIB)
+
+# The files on which youngest is run.
+SRC_NON_GEN = $(filter-out src/credits.cc src/prefix.cc src/version.cc, $(SRC))
+
+# The object files
+OBJ_CONFIG  =# $(OBJDIR)/config.o
+DOBJ_CONFIG =# $(DOBJDIR)/config.o
+OBJ_YADEX   = $(addprefix $(OBJDIR)/,  $(addsuffix .o, $(MODULES_YADEX)))
+DOBJ_YADEX  = $(addprefix $(DOBJDIR)/, $(addsuffix .o, $(MODULES_YADEX)))
+OBJ_ATCLIB  = $(addprefix $(OBJDIR_ATCLIB)/,  $(addsuffix .o,$(MODULES_ATCLIB)))
+DOBJ_ATCLIB = $(addprefix $(DOBJDIR_ATCLIB)/, $(addsuffix .o,$(MODULES_ATCLIB)))
+
+# The game definition files.
+YGD = $(addprefix ygd/,							\
+	doom.ygd	doom02.ygd	doom04.ygd	doom05.ygd	\
+	doom2.ygd	doompr.ygd	heretic.ygd	hexen.ygd	\
+	strife.ygd	strife10.ygd)
+
+# Files that are used with scripts/process to
+# generate files that are included in the
+# distribution archive.
+DOC1_SRC =				\
+	docsrc/README			\
+	docsrc/README.doc
+
+# Files that are used with scripts/process to
+# generate files that go in the doc/ directory
+# and are NOT included in the archive.
+DOC2_SRC_HTML =				\
+	docsrc/advanced.html		\
+	docsrc/contact.html		\
+	docsrc/credits.html		\
+	docsrc/deu_diffs.html		\
+	docsrc/editing_docs.html	\
+	docsrc/faq.html			\
+	docsrc/feedback.html		\
+	docsrc/getting_started.html	\
+	docsrc/hackers_guide.html	\
+	docsrc/help.html		\
+	docsrc/index.html		\
+	docsrc/keeping_up.html		\
+	docsrc/legal.html		\
+	docsrc/packagers_guide.html	\
+	docsrc/palette.html		\
+	docsrc/reporting.html		\
+	docsrc/tips.html		\
+	docsrc/trivia.html		\
+	docsrc/trouble.html		\
+	docsrc/users_guide.html		\
+	docsrc/wad_specs.html		\
+	docsrc/ygd.html
+
+DOC2_SRC_MISC =				\
+	docsrc/yadex.6			\
+#	docsrc/yadex.lsm\
+
+# Files that must be put in the distribution
+# archive. Most (but not all) are generated from
+# $(DOC1_SRC_*) into the base directory.
+DOC1 = FAQ README doc/README
+
+# Files that go in the doc/ directory and must
+# NOT be put in the distribution archive. Most
+# are either generated from $(DOC2_SRC_*) or
+# symlinked for docsrc/*.png.
+DOC2 = $(addprefix doc/, $(PIX) $(notdir $(DOC2_SRC_HTML) $(DOC2_SRC_MISC)))
+
+# Misc. other files that must be put in the
+# distribution archive.
+MISC_FILES =								\
+	boost/boost/config.hpp						\
+	boost/boost/config/compiler/borland.hpp				\
+	boost/boost/config/compiler/comeau.hpp				\
+	boost/boost/config/compiler/common_edg.hpp			\
+	boost/boost/config/compiler/compaq_cxx.hpp			\
+	boost/boost/config/compiler/gcc.hpp				\
+	boost/boost/config/compiler/greenhills.hpp			\
+	boost/boost/config/compiler/hp_acc.hpp				\
+	boost/boost/config/compiler/intel.hpp				\
+	boost/boost/config/compiler/kai.hpp				\
+	boost/boost/config/compiler/metrowerks.hpp			\
+	boost/boost/config/compiler/mpw.hpp				\
+	boost/boost/config/compiler/sgi_mipspro.hpp			\
+	boost/boost/config/compiler/sunpro_cc.hpp			\
+	boost/boost/config/compiler/vacpp.hpp				\
+	boost/boost/config/compiler/visualc.hpp				\
+	boost/boost/config/platform/aix.hpp				\
+	boost/boost/config/platform/beos.hpp				\
+	boost/boost/config/platform/bsd.hpp				\
+	boost/boost/config/platform/cygwin.hpp				\
+	boost/boost/config/platform/hpux.hpp				\
+	boost/boost/config/platform/irix.hpp				\
+	boost/boost/config/platform/linux.hpp				\
+	boost/boost/config/platform/macos.hpp				\
+	boost/boost/config/platform/solaris.hpp				\
+	boost/boost/config/platform/win32.hpp				\
+	boost/boost/config/posix_features.hpp				\
+	boost/boost/config/select_compiler_config.hpp			\
+	boost/boost/config/select_platform_config.hpp			\
+	boost/boost/config/select_stdlib_config.hpp			\
+	boost/boost/config/stdlib/dinkumware.hpp			\
+	boost/boost/config/stdlib/libstdcpp3.hpp			\
+	boost/boost/config/stdlib/modena.hpp				\
+	boost/boost/config/stdlib/msl.hpp				\
+	boost/boost/config/stdlib/roguewave.hpp				\
+	boost/boost/config/stdlib/sgi.hpp				\
+	boost/boost/config/stdlib/stlport.hpp				\
+	boost/boost/config/stdlib/vacpp.hpp				\
+	boost/boost/config/suffix.hpp					\
+	boost/boost/config/user.hpp					\
+	boost/boost/smart_ptr.hpp					\
+	boost/boost/static_assert.hpp					\
+	boost/boost/utility.hpp						\
+	boost/boost/utility/base_from_member.hpp			\
+	boost/boost/utility_fwd.hpp					\
+	cache/copyright.man						\
+	cache/copyright.txt						\
+	cache/pixlist							\
+	cache/srcdate							\
+	cache/uptodate							\
+	configure							\
+	docsrc/copyright						\
+	CHANGES								\
+	COPYING								\
+	COPYING.LIB							\
+	GNUmakefile							\
+	Makefile							\
+	TODO								\
+	VERSION								\
+	yadex.cfg							\
+	yadex.dep
+
+# The images used in the HTML doc. FIXME: "<img"
+# and "src=" have to be on the same line. These
+# are symlinked into doc/ when $(DOC2) is made.
+PIX = $(shell cat cache/pixlist)
+
+# The script files.
+SCRIPTS = $(addprefix scripts/,	\
+	copyright		\
+	ftime.1			\
+	ftime.c			\
+	install.c		\
+	mkinstalldirs		\
+	notexist.c		\
+	process			\
+	youngest)
+
+# The patches
+PATCHES = $(addprefix patches/,	\
+	README			\
+	1.5.0_gcc27.diff)
+
+# All files that must be put in the distribution archive.
+ARC_FILES = $(sort $(DOC1) $(DOC1_SRC) $(DOC2_SRC_HTML) $(DOC2_SRC_MISC)\
+	$(MISC_FILES) $(addprefix docsrc/, $(PIX)) $(SCRIPTS) $(SRC) $(YGD)\
+	$(PATCHES))
+
+# The "root" directory of the archives. The
+# basename of the archives is also based on this.
+ARCHIVE := yadex-$(VERSION)
+ARCPREV := yadex-$(VERPREV)
+ARCDIFF := yadex-$(VERSION).diff
+
+# Cosmetic
+CFLAGS    := $(strip $(CFLAGS))
+DCFLAGS   := $(strip $(DCFLAGS))
+CXXFLAGS  := $(strip $(CXXFLAGS))
+DCXXFLAGS := $(strip $(DCXXFLAGS))
+LDFLAGS   := $(strip $(LDFLAGS))
+DLDFLAGS  := $(strip $(DLDFLAGS))
+
+
+########################################################################
+#
+#	Targets for
+#	end users.
+#
+########################################################################
+
+.PHONY: all
+all: doc yadex.dep yadex $(YGD)
+
+.PHONY: yadex
+yadex: $(OBJDIR)/yadex
+
+$(OBJDIR)/yadex: $(OBJ_CONFIG) $(OBJ_YADEX) $(OBJ_ATCLIB) $(MAKEFILE)
+	@echo "** Linking Yadex"
+	$(CXX) $(OBJ_CONFIG) $(OBJ_YADEX) $(OBJ_ATCLIB) -o $@		\
+	  -L$(X11LIBDIR) -lX11 -lm -lc $(LDFLAGS)
+
+.PHONY: test
+test:
+	$(OBJDIR)/yadex $(A)
+
+.PHONY: install
+install: $(OBJDIR)/install
+	@scripts/mkinstalldirs $(BINDIR)
+	@scripts/mkinstalldirs $(ETCDIR)
+	@scripts/mkinstalldirs $(MANDIR)
+	@scripts/mkinstalldirs $(MANDIR)/man6
+	@scripts/mkinstalldirs $(SHAREDIR)
+	$(OBJDIR)/install -m 755 $(OBJDIR)/yadex $(BINDIR)/yadex-$(VERSION)
+	rm -f $(BINDIR)/yadex
+	ln -s yadex-$(VERSION) $(BINDIR)/yadex
+	$(OBJDIR)/install -m 644 doc/yadex.6 $(MANDIR)/man6/yadex-$(VERSION).6
+	rm -f $(MANDIR)/man6/yadex.6
+	ln -s yadex-$(VERSION).6 $(MANDIR)/man6/yadex.6
+	$(OBJDIR)/install -m 644 -d $(SHAREDIR) $(YGD)
+	$(OBJDIR)/install -m 644 -d $(ETCDIR) yadex.cfg
+	@echo "---------------------------------------------------------------"
+	@echo "  Yadex is now installed."
+	@echo
+	@echo "  Before you run it, enter the paths to your iwads in"
+	@echo "  $(ETCDIR)/yadex.cfg or ~/.yadex/yadex.cfg."
+	@echo "  When you're done, type \"yadex\" to start."
+	@echo "  If you're confused, take a look at doc/index.html."
+	@echo
+	@echo "  Happy editing !"
+	@echo "---------------------------------------------------------------"
+
+.PHONY: clean
+clean:
+	rm -f $(OBJ_CONFIG) $(OBJ_YADEX) $(OBJ_ATCLIB) $(OBJDIR)/yadex
+	rm -f $(DOBJ_CONFIG) $(DOBJ_YADEX) $(DOBJ_ATCLIB) $(DOBJDIR)/yadex
+	rm -f $(OBJDIR)/ftime
+	rm -f $(OBJDIR)/install
+	rm -f $(OBJDIR)/notexist
+	rm -f $(OBJDIR)
+	rm -f $(DOBJDIR)
+	rm -rf doc
+
+.PHONY: dclean
+dclean:
+	rm -rf $(DOBJPHYSDIR)
+	rm -f $(DOBJDIR)
+
+.PHONY: doc
+doc: cache/pixlist docdirs $(DOC1) doc2
+
+# Have to put it separately because evaluation
+# of $(DOC2) requires cache/pixlist to exist.
+.PHONY: doc2
+doc2: $(DOC2)
+
+.PHONY: help
+help:
+	@echo User targets:
+	@echo "make [all]           Build everything"
+	@echo "make yadex           Build Yadex"
+	@echo "make test [A=args]   Test Yadex"
+	@echo "make install         Install everything"
+	@echo "make showconf        Show current configuration"
+	@echo
+	@echo Hacker targets:
+	@echo "make dall            Build debug version of everything"
+	@echo "make dyadex          Build debug version of Yadex"
+	@echo "make dtest [A=args]  Test debug version of Yadex"
+	@echo "make dg              Run debug version of Yadex through gdb"
+	@echo "make dd              Run debug version of Yadex through ddd"
+	@echo "make doc             Update doc"
+	@echo "make man             View man page with man"
+	@echo "make dvi             View man page with xdvi"
+	@echo "make ps              View man page with gv"
+	@echo "make dist            Create distribution archive"
+	@echo "make save            Create backup archive"
+
+
+########################################################################
+#
+#	Targets meant for
+#	hackers only.
+#
+########################################################################
+
+# d: Compile and run
+.PHONY: d
+d: dyadex dtest
+
+.PHONY: save
+save:
+	tar -cjvf yadex-$$(date '+%Y%m%d').tar.bz2			\
+		--exclude "*.wad"					\
+		--exclude "*.zip"					\
+		--exclude "core"					\
+		--exclude "dos/*"					\
+		--exclude "obj"						\
+		--exclude "dobj"					\
+		--exclude "old/*"					\
+		--exclude "*~"						\
+		--exclude "*.bak"					\
+		--exclude "web/arc"					\
+		--exclude yadex-$$(date '+%Y%m%d').tar.bz2		\
+		.
+
+.PHONY: dall
+dall: yadex.dep dyadex $(YGD)
+
+.PHONY: dyadex
+dyadex: $(DOBJDIR)/yadex
+	
+$(DOBJDIR)/yadex: $(DOBJ_CONFIG) $(DOBJ_YADEX) $(DOBJ_ATCLIB) $(MAKEFILE)
+	@echo "** Linking Yadex"
+	$(CXX) $(DOBJ_CONFIG) $(DOBJ_YADEX) $(DOBJ_ATCLIB) -o $@	\
+	  -L$(X11LIBDIR) -lX11 -lm -lc $(DLDFLAGS)
+
+.PHONY: dtest
+dtest:
+	$(DOBJDIR)/yadex $(A)
+	gprof $(DOBJDIR)/yadex >gprof.out
+
+.PHONY: dg
+dg:
+	gdb $(DOBJDIR)/yadex
+	
+.PHONY: dd
+dd:
+	ddd $(DOBJDIR)/yadex
+
+.PHONY: asm
+asm: $(addprefix $(OBJDIR)/, $(addsuffix .S, $(MODULES_YADEX)))
+
+# Generate the distribution archives. Requires GNU tar,
+# GNU cp, gzip and optionally bzip2 (if distbz2 is
+# uncommented).
+.PHONY: dist
+dist: changes distimage distgz distdiff #distbz2
+	@echo "** Removing distribution image tree $(ARCHIVE)"
+	rm -r $(ARCHIVE)
+
+.PHONY: distimage
+distimage: all $(ARC_FILES)
+	@echo "** Creating distribution image tree $(ARCHIVE)"
+	rm -rf $(ARCHIVE)
+	scripts/mkinstalldirs $(ARCHIVE)
+	@tar -cf - $(ARC_FILES) | (cd $(ARCHIVE); tar -xf -)
+
+.PHONY: distgz
+distgz: distimage
+	@echo "** Creating tar.gz distribution"
+	tar -czf $(ARCHIVE).tar.gz $(ARCHIVE)
+
+.PHONY: distbz2
+distbz2: distimage
+	@echo "** Creating .tar.bz2 distribution"
+	tar -cIf $(ARCHIVE).tar.bz2 $(ARCHIVE)
+
+.PHONY: distdiff
+TMP0    = $$HOME/tmp
+TMPPREV = $(TMP0)/$(ARCPREV)
+TMPCURR = $(TMP0)/$(ARCHIVE)
+distdiff:
+	@echo "** Building the diff distribution"
+	@echo "Creating the diff"
+	rm -rf $(TMPPREV) $(TMPCURR) $(TMPDIFF)
+	mkdir -p $(TMP0)
+	tar -xzf                  $(ARCHIVE).tar.gz -C $(TMP0)
+	tar -xzf ../yadex-arc/pub/$(ARCPREV).tar.gz -C $(TMP0)
+	scripts/process docsrc/README.diff >$(TMP0)/$(ARCDIFF)
+	echo >>$(TMP0)/$(ARCDIFF)
+	cd $(TMP0) && (diff -uaNr $(ARCPREV) $(ARCHIVE) >>$(ARCDIFF) || true)
+	@# KLUDGE - On my system, just "! grep" makes make choke
+	true; ! grep "^Binary files .* and .* differ" $(TMP0)/$(ARCDIFF)
+	gzip -f $(TMP0)/$(ARCDIFF)
+	@echo "Verifying the diff"
+	cd $(TMPPREV) && gzip -d <../$(ARCDIFF).gz | patch -p1
+	@# FIXME remove -N after 1.6 is done, it's there because
+	@# uptodate has been moved between 1.5 and 1.6 and since
+	@# it's empty it remains in $(ARCPREV).
+	cd $(TMP0) && diff -rP $(ARCHIVE) $(ARCPREV)
+	mv $(TMP0)/$(ARCDIFF).gz .
+	@echo "Cleaning up"
+	cd $(TMP0) && rm -rf $(ARCPREV)
+	cd $(TMP0) && rm -rf $(ARCHIVE)
+
+.PHONY: showconf
+showconf:
+	@echo "ARCHIVE            \"$(ARCHIVE)\""
+	@echo "BINDIR             \"$(BINDIR)\""
+	@echo "CC                 \"$(CC)\""
+	@echo "CFLAGS             \"$(CFLAGS)\""
+	@echo "CXX                \"$(CXX)\""
+	@echo "CXXFLAGS           \"$(CXXFLAGS)\""
+	@echo "DCFLAGS            \"$(DCFLAGS)\""
+	@echo "DCXXFLAGS          \"$(DCXXFLAGS)\""
+	@echo "DLDFLAGS           \"$(DLDFLAGS)\""
+	@echo "ETCDIR             \"$(ETCDIR)\""
+	@echo "ETCDIRNV           \"$(ETCDIRNV)\""
+	@echo "HAVE_GETTIMEOFDAY  \"$(HAVE_GETTIMEOFDAY)\""
+	@echo "HAVE_NANOSLEEP     \"$(HAVE_NANOSLEEP)\""
+	@echo "HAVE_SNPRINTF      \"$(HAVE_SNPRINTF)\""
+	@echo "HAVE_USLEEP        \"$(HAVE_USLEEP)\""
+	@echo "LDFLAGS            \"$(LDFLAGS)\""
+	@echo "MANDIR             \"$(MANDIR)\""
+	@echo "OS                 \"$(OS)\""
+	@echo "PREFIX             \"$(PREFIX)\""
+	@echo "SHAREDIR           \"$(SHAREDIR)\""
+	@echo "SHAREDIRNV         \"$(SHAREDIRNV)\""
+	@echo "SHELL              \"$(SHELL)\""
+	@echo "SYSTEM             \"$(SYSTEM)\""
+	@echo "VERSION            \"$(VERSION)\""
+	@echo "X11INCLUDEDIR      \"$(X11INCLUDEDIR)\""
+	@echo "X11LIBDIR          \"$(X11LIBDIR)\""
+	@echo "CXX --version      \"`$(CXX) --version`\""
+	@echo "CC --version       \"`$(CC) --version`\""
+	@echo "shell              \"$$SHELL\""
+	@echo "uname              \"`uname`\""
+
+
+########################################################################
+#
+#	Internal targets, not meant
+#	to be invoked directly
+#
+########################################################################
+
+# If Makefile.config doesn't exist, give a hint...
+$(OBJDIR)/Makefile.config:
+	@echo "Sorry guv'nor, but... did you run ./configure ?" >&2
+	@false
+
+$(OBJDIR)/files_etc.man: $(OBJDIR)/config.etc $(MAKEFILE)
+	sed 's/%v/$(VERSION)/g; s,.*,.B &/yadex.cfg,' $< >$@
+
+$(OBJDIR)/files_share.man: $(OBJDIR)/config.share $(MAKEFILE)
+	sed 's/%v/$(VERSION)/g; s,.*,.BI &/ game .ygd,' $< >$@
+
+# Dependencies of the modules of Yadex
+# -Y is here to prevent the inclusion of dependencies on
+# /usr/include/*.h etc. As a side-effect, it generates many
+# warnings, hence "2>/dev/null".
+#
+# The purpose of the awk script is to transform this input :
+#
+#   src/foo.o: src/whatever.h
+#
+# into this output :
+#
+#   obj/0/foo.o: src/whatever.h
+#   dobj/0/foo.o: src/whatever.h
+#
+# Note: the modules of Atclib are not scanned as they all
+# depend on $(HEADERS_ATCLIB) and nothing else.
+
+yadex.dep: $(SRC_NON_GEN)
+	@echo "Generating $@"
+	@makedepend -f- -Y -Iatclib $(SRC_NON_GEN) 2>/dev/null	\
+		| awk 'sub (/^src/, "") == 1 {				\
+				print "'$(OBJDIR)'" $$0;		\
+				print "'$(DOBJDIR)'" $$0;		\
+				next;					\
+			}' >$@
+
+cache/copyright.man: $(MAKEFILE) scripts/copyright docsrc/copyright
+	scripts/copyright -m docsrc/copyright >$@
+
+cache/copyright.txt: $(MAKEFILE) scripts/copyright docsrc/copyright
+	scripts/copyright -t docsrc/copyright | sed 's/^./    &/' >$@
+
+# The YYYY-MM-DD date indicated in the parentheses after the
+# version number is the mtime of the most recent source file
+# (where "being a source file" is defined as "being listed in
+# $(SRC_NON_GEN)"). That string is the output of a perl script,
+# scripts/youngest. Since perl is not necessarily installed on
+# all machines, we cache that string in the file cache/srcdate
+# and include that file in the distribution archive. If we
+# didn't do that, people who don't have perl would be unable to
+# build Yadex.
+#
+# Conceptually, cache/srcdate depends on $(SRC_NON_GEN) and
+# doc/*.html depend on cache/srcdate. However, we can't write the
+# makefile that way because if we did, that would cause two
+# problems. Firstly every time a source file is changed,
+# scripts/youngest would be ran, most of the time for nothing
+# since its output is always the same, unless it's never been
+# run today. Secondly, cache/srcdate being just generated, it's
+# more recent than the content of the doc/ directory. The result
+# would be that the entire doc/ directory would be rebuilt every
+# time a single source file is changed, which is guaranteed to
+# have an unnerving effect on the hacker at the keyboard.
+#
+# Part of the solution is to systematically force the mtime of
+# cache/srcdate to 00:00, today. Thus, cache/srcdate always looks
+# older than the content of the doc/ directory, unless it's not
+# been refreshed yet today.
+#
+# But that's not enough because then cache/srcdate also looks
+# always older than the source files it depends on, and thus
+# make attempts to regenerate it every time make is invoked at
+# all, which would render the very existence of cache/srcdate
+# useless. That's why we have another file, cache/uptodate, that
+# we touch to keep track of the time when we last generated
+# cache/srcdate.
+#
+# If there was a such thing as _date-only_ dependencies, I could
+# get away with just this :
+#
+# cache/srcdate: scripts/youngest
+# cache/srcdate <date_dependency_operator> $(SRC_NON_GEN)
+#         if perl -v >/dev/null 2>&1; then\
+#           scripts/youngest >$@;\
+#         else\
+#           blah...
+# doc/*.html <date_dependency_operator> cache/srcdate
+#         blah...
+#
+# That would save two calls to "touch", one intermediary
+# dependency (cache/uptodate) and a lot of obfuscation.
+cache/srcdate: cache/uptodate
+
+cache/uptodate: scripts/youngest $(SRC_NON_GEN)
+	@mkdir -p cache
+	@if perl -v >/dev/null 2>&1; then				\
+	  echo Generating cache/srcdate;				\
+	  scripts/youngest $(SRC_NON_GEN) >cache/srcdate;		\
+	  touch -t `date '+%m%d'`0000 cache/srcdate;			\
+	elif [ -r cache/srcdate ]; then					\
+	  echo Perl not available. Keeping old cache/srcdate;		\
+	else								\
+	  echo Perl not available. Creating bogus cache/srcdate;	\
+	  date '+%Y-%m-%d' >cache/srcdate;				\
+	fi
+	@touch $@;
+
+# To compile the modules of Yadex
+# (normal and debugging versions)
+include yadex.dep
+
+# It's simpler to copy config.cc into src/ than to have a
+# compilation rule for just one file.
+src/config.cc: $(OBJDIR)/config.cc
+	cp -p $< $@
+
+src/config.h: $(OBJDIR)/config.h
+	cp -p $< $@
+
+$(OBJDIR)/%.o: src/%.cc
+	$(CXX) -c -Iatclib -Iboost -I$(X11INCLUDEDIR) $(CXXFLAGS) $< -o $@
+
+$(DOBJDIR)/%.o: src/%.cc
+	$(CXX) -c -Iatclib -Iboost -I$(X11INCLUDEDIR) $(DCXXFLAGS) $< -o $@
+
+# To compile the modules of Atclib
+# (normal and debugging versions)
+$(OBJDIR_ATCLIB)/%.o: atclib/%.c $(HEADERS_ATCLIB)
+	$(CC) -c $(CFLAGS) $< -o $@
+
+$(DOBJDIR_ATCLIB)/%.o: atclib/%.c $(HEADERS_ATCLIB)
+	$(CC) -c $(DCFLAGS) $< -o $@
+
+# To see the generated assembly code
+# for the modules of Yadex
+$(OBJDIR)/%.S: src/%.cc $(MAKEFILE)
+	$(CXX) $(CXXFLAGS) -S -fverbose-asm -Iatclib -Iboost -I$(X11INCLUDEDIR)\
+	  $< -o $@
+
+# A source file containing the credits
+src/credits.cc: $(MAKEFILE) docsrc/copyright scripts/copyright
+	@echo Generating $@
+	@echo '// DO NOT EDIT -- generated from docsrc/copyright' >$@
+	scripts/copyright -c docsrc/copyright >>$@
+
+# A source file containing just the date of the
+# most recent source file and the version number
+# (found in ./VERSION)
+src/version.cc: $(SRC_NON_GEN) VERSION cache/srcdate $(MAKEFILE)
+	@echo Generating $@
+	@printf '// DO NOT EDIT -- generated from VERSION\n\n' >$@
+	@printf "extern const char *const yadex_source_date = \"%s\";\n" \
+		`cat cache/srcdate` >>$@
+	@printf "extern const char *const yadex_version = \"%s\";\n" 	\
+		"$(VERSION)" >>$@
+
+
+# -------- Doc-related stuff --------
+
+docdirs:
+	@if [ ! -d doc ]; then mkdir doc; fi
+
+cache/pixlist: $(DOC2_SRC_HTML)
+	@echo Generating $@
+	@mkdir -p cache
+	@if perl -v >/dev/null 2>/dev/null; then			\
+	  perl -ne '@l = m/<img\s[^>]*src="?([^\s">]+)/io;		\
+	    print "@l\n" if @l;' $(DOC2_SRC_HTML) | sort | uniq >$@;	\
+	elif [ -f $@ ]; then						\
+	  echo "Sorry, you need Perl to refresh $@. Keeping old $@.";	\
+	else								\
+	  echo "Sorry, you need Perl to create $@. Creating empty $@.";	\
+	  touch $@;							\
+	fi
+
+events.html: ev evhtml
+	evhtml -- -n $< >$@
+
+events.txt: events.html
+	lynx -dump $< >$@
+
+changes/changes.html: changes/*.log log2html RELEASE
+	./log2html -- -r `cat RELEASE` -- $$(ls -r changes/*.log) >$@
+	
+# changes - update the changelog
+.PHONY: changes
+changes: changes/changes.html
+	w3m -dump -cols 72 $< >CHANGES
+
+# cns - view the changelog with Netscape
+.PHONY: cns
+cns:
+	netscape -remote "openURL(file:$$(pwd)/changes/changes.html,new-window)"
+
+# clynx - view the changelog with Lynx
+.PHONY: clynx
+clynx:
+	lynx changes/changes.html
+
+# cless - view the changelog with less
+.PHONY: cless
+cless:
+	less CHANGES
+
+# man - view the man page with man
+.PHONY: man
+man: doc/yadex.6
+	man -l $^
+
+# dvi - view the man page with xdvi
+.PHONY: dvi
+dvi: doc/yadex.dvi
+	xdvi $^ 
+
+# ps - view the man page with gv
+.PHONY: ps
+ps: doc/yadex.ps
+	gv $^
+
+# Use docsrc/faq.html and not directly
+# doc/faq.html because we don't want FAQ to be
+# remade at first build time.
+FAQ: docsrc/faq.html
+	scripts/process $< >cache/faq.html
+	links -width 72 -dump cache/faq.html >$@
+	rm cache/faq.html
+
+doc/yadex.dvi: doc/yadex.6
+	groff -Tdvi -man $^ >$@
+
+doc/yadex.ps: doc/yadex.6
+	groff -Tps -man $^ >$@
+	
+
+# Generate the doc by filtering them through scripts/process
+PROCESS =				\
+	VERSION				\
+	cache/copyright.man		\
+	cache/copyright.txt		\
+	cache/srcdate			\
+	scripts/process			\
+	$(OBJDIR)/ftime			\
+	$(OBJDIR)/files_etc.man		\
+	$(OBJDIR)/files_share.man	\
+	$(OBJDIR)/notexist
+
+doc/yadex.6: docsrc/yadex.6 $(PROCESS)
+	@echo Generating $@
+	@scripts/process $< >$@
+
+doc/README: docsrc/README.doc $(PROCESS)
+	@echo Generating $@
+	@scripts/process $< >$@
+
+%: docsrc/% $(PROCESS)
+	@echo Generating $@
+	@scripts/process $< >$@
+
+doc/%.html: docsrc/%.html $(PROCESS)
+	@echo Generating $@
+	@scripts/process $< >$@
+
+# The images are just symlinked from docsrc/ to doc/
+doc/%.png: docsrc/%.png
+	@rm -f $@
+	@ln -s ../$< $@
+
+$(OBJDIR)/ftime: scripts/ftime.c
+	$(CC) $< -o $@
+
+$(OBJDIR)/install: scripts/install.c
+	$(CC) $< -o $@
+
+$(OBJDIR)/notexist: scripts/notexist.c
+	$(CC) $< -o $@
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Makefile	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,10 @@
+# This one is for users of vanilla make.
+# The real makefile is GNUmakefile.
+
+all:
+	@echo Sorry, you need GNU make to build Yadex. GNU make can be
+	@echo downloaded freely from ftp://ftp.gnu.org/gnu/make/. To
+	@echo install it, type \"./configure\; make\; make install\".
+	@echo By default, it installs as /usr/local/bin/make so use
+	@echo that instead of \"make\" when building Yadex.
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/README	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,141 @@
+Yadex 1.7.0 (2003-12-28)
+
+WHAT IS YADEX ?
+    Yadex is a Doom level (wad) editor for Unix systems running X,
+    including Linux. It supports Doom, Doom II, Ultimate Doom, Final
+    Doom, Heretic, Doom press release pre beta and also, in a more or
+    less limited way, Hexen, Strife and Doom alpha. It is available
+    under the terms of the GPL.
+
+PREREQUISITES
+    You need :
+    - Some flavour of Unix (known to work with AIX, FreeBSD, HP-UX,
+      Irix, Linux, NetBSD, OpenBSD, OpenUnix, QNX and Solaris),
+    - X11R6 or X11R5 and a display of at least 640x480,
+    - a Doom/Doom II/Heretic/Strife iwad (shareware/demo is OK),
+    - GNU make (vanilla make won't do),
+    - a standard C compiler (ISO 9899:1990),
+    - a standard C++ compiler,
+    - hypot() and either nanosleep() or usleep().
+
+BUILDING AND INSTALLING
+    To install in /usr/local :
+
+                    ./configure
+                    make
+                    su -c 'make install'
+
+    To install somewhere else, for example in ~/yadex :
+
+                    ./configure --prefix ~/yadex
+                    make
+                    make install
+
+    To force the use of a particular C/C++ compiler :
+
+                    ./configure --cc gcc-3.3 --cxx g++-3.3 
+                    make
+                    make install
+
+    Got problems getting Yadex to compile ? See doc/faq.html.
+    Got no problem ? Read the FAQ anyway. See doc/faq.html.
+    
+    Beware, the installation OVERWRITES the following files (assuming
+    you're installing in /usr/local) :
+           /etc/yadex/1.7.0/yadex.cfg
+           /usr/local/bin/yadex
+           /usr/local/bin/yadex-1.7.0
+           /usr/local/man/man6/yadex.6
+           /usr/local/man/man6/yadex-1.7.0.6
+           /usr/local/share/games/yadex/1.7.0/doom.ygd
+           /usr/local/share/games/yadex/1.7.0/doom02.ygd
+           /usr/local/share/games/yadex/1.7.0/doom04.ygd
+           /usr/local/share/games/yadex/1.7.0/doom05.ygd
+           /usr/local/share/games/yadex/1.7.0/doom2.ygd 
+           /usr/local/share/games/yadex/1.7.0/doompr.ygd
+           /usr/local/share/games/yadex/1.7.0/heretic.ygd
+           /usr/local/share/games/yadex/1.7.0/hexen.ygd
+           /usr/local/share/games/yadex/1.7.0/strife.ygd
+           /usr/local/share/games/yadex/1.7.0/strife10.ygd
+
+CONFIGURING AND RUNNING
+    Before you run Yadex, you need to tell it where to find your iwads.
+    Assuming you have installed in /usr/local, open
+    /etc/yadex/1.7.0/yadex.cfg with your favourite text editor and
+    insert the appropriate values for the parameters "iwad1", "iwad2",
+    etc. If you don't want Doom II to be the default iwad, also change
+    the value of the "game" parameter.
+
+    You can now run Yadex by typing :
+    
+			  yadex
+
+    A "yadex:" prompt should show. At that prompt, type this :
+    
+			  e map01
+
+    or this :
+
+			  e e1m1
+
+    Have fun !
+
+DOCUMENTATION
+    There is a man page and quite a lot of documentation, most of it in
+    HTML format. Start at :
+
+                          doc/index.html
+
+    If you're upgrading from a previous version of Yadex, please read
+    carefully CHANGES.
+
+STATUS
+    Yadex is work in progress. It still lacks important features like a
+    better interface, cut-and-paste, undo/redo, support for Boom and
+    many more. I know. They will come faster if you help. The source
+    code is a horrible mess. I'm not proud of it. Be indulgent.
+
+LEGAL
+    1. Yadex
+
+    Parts copyright Andrew Apted 2000-2001, GNU GPL v2
+    Parts copyright André Majorel 1997-2003, GNU GPL v2
+    Parts copyright Matthew W. Miller 2000, GNU GPL v2
+    Parts written by Raphaël Quinet, public domain
+    Parts written by Brendon Wyber, public domain
+
+    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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+    2. Atclib
+
+    The Yadex distribution includes a subset of Atclib.
+    
+    Atclib is copyright André Majorel 1995-1999 and distributed under
+    the terms of version 2 of the GNU Library General Public License.
+
+    3. Boost
+
+    The Yadex distribution includes a subset of Boost 1.25.0. Boost
+    1.25.0 is copyright various authors and released under the following
+    terms : Permission to copy, use, modify, sell and distribute this
+    software is granted provided this copyright notice appears in all
+    copies.  This software is provided "as is" without express or
+    implied warranty, and with no claim as to its suitability for any
+    purpose.
+
+CONTACT
+    See doc/contact.html for addresses.
+
+AYM 2003-12-28
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/TODO	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,2366 @@
+----------------------------------------
+
+TO-DO LIST FOR YADEX
+
+----------------------------------------
+
+
+General
+- Automatically adapt to level to edit; if it's a Doom level (ExMy),
+  reread doom.wad, if it's a Doom II level (MAPnn), reread doom2.wad.
+  what if it's a Heretic level ? It must be possible to tell a Heretic
+  level by the special sector & thing types.
+
+Command line
+- Add option -e like in sed and Perl. Auto quit at end or not ?
+- Add option -f like in sed ?
+- Unix version recognizes -V but does not list it in the usage.
+
+Configuration file
+- Add operator ".=" (E.G. "iwad_dir .= ,/foo/bar"). Perhaps implement
+  real lists. Perhaps not.
+- Comments are not allowed if not at the beginning of a line
+- New option --print-config-path or --cfg-dirs to print the config file
+  search path and exit
+
+Variables
+- Make variables objects instead of C++ variables. It should not be
+  necessary to recompile everything each time you want to add a
+  variable. Still be able to generate a list of all known variables...
+- Better support for changing of configuration variables from the
+  editor.
+- Add a way to set variables from the command line ("-sname=value" or
+  something like that).
+- Setting options: add a "set name value" prompt command.
+- Setting options: make "set" stop after each screenful.
+- Setting options: modify the "Preferences" menu so that all options can
+  be changed from there and modifications are saved.
+
+Game definitions
+- Move thing groups colour from .ygd to .cfg.
+- Generalize the principle of game by replacing iwad[123]= by iwad= in
+  different sections of the .cfg.
+- Fix TranslateToDoomColor().
+- -g should accept anything as long as <anything>.ygd exists.
+- It is prob. possible to crash the program by entering weird things in
+  LoadGameDefs. For example, shortdesc is not truncated and the current
+  number of "raise floor" types will probably make the menu "overflow"
+  the screen. DisplayMenu() should fix the y-offset if necessary.
+- It is possible to define the same group twice or use a non existing
+  group.
+- LoadGameDefs: try to waste less memory if possible.
+- FreeGameDefs(): apparently does not unallocate everything. It's
+  immaterial since it's only called just before exiting but I'll have to
+  fix it one day.
+- Enter two iwad names for the same game (E.G. doom.wad and doom1.wad).
+- Add list of animated flats and textures.
+- Add "height" and "is_obstacle" fields to things definitions.
+- Add flat width and height.
+- Add min and max player and deathmatch starts.
+- Add default level names.
+- Move the definition of special sector tags out of the exe and into the
+  ygd files.
+- Gadget: add level names (E.G. "E1M1" -> "Hangar").
+- The basename need not be in the configuration file; it should be in
+  the ygd (E.G. iwad_base = "doom.wad,doom1.wad")
+- The .ygd collection has grown so large that it has become difficult to
+  maintain. For example, changes made to strife.ygd must be propagated
+  to strife10.ygd by hand. There is a lot of duplication : the 150 kB of
+  game definition data boil down to 30 kB after piping into sort | uniq.
+  I would like to implement an include directive and reorganize
+  accordingly :
+    _boom.ygd     in Boom but not in Doom*
+    _doom.ygd     in all versions of Doom >= 1.0
+    _doom16.ygd   in Doom 1.666 and above (linedef types)
+    _doom2.ygd    in Doom II (things)
+    _heretic.ygd  in Heretic only (things, sector types)
+    _mbf.ygd      in MBF but not in Boom
+    _strife.ygd   in all versions of Strife
+    _tgroups.ygd  all things groups ?
+    _zdoom.ygd    in ZDoom but not in Boom
+    doom.ygd      include _doom; include _doom16
+    doom04.ygd    ?
+    doom05.ygd    ?
+    doompr.ygd    ?
+    doom2.ygd     include _doom; include _doom16; include _doom2
+    hacx.ygd      ??
+    heretic.ygd   include _doom; include _doom16/_doom2 (?); include _heretic
+    hexen.ygd     no change
+    plutonia.ygd  include doom2: iwad_base plutonia.wad [solves Colin's pb]
+    strife.ygd    include _strife; texture_format strife11
+    strife10.ygd  include _strife; texture_format normal
+    tnt.ygd       include doom2: iwad_base tnt.wad [solves Colin's pb]
+  The rules for locating of relative includes :
+    1. search the current directory,
+    2. search the directory where the parent ygd file is,
+    3. search the standard directories.
+  If an include has a bad magic, don't abort, just keep searching for
+  one that has the appropriate magic (but warn). If an include was not
+  found just print a warning and continue ?
+- Allow overriding of a previous linedef type / thing type / sector type
+  definition (currently it just *adds* and, since the new definition is
+  at the end the of list, it's *ignored*). Possibly with an option to
+  warn about such redefinitions.
+- New option -Y (or -y or -G ?) to insert a directory at the beginning
+  of the .ygd files search path. Perhaps -Y- to clear the path (think
+  -I-). Add it to "make test" and "make dtest".
+- New option --print-ygd-path or --ygd-dirs to print the ygd file search
+  path and exit.
+
+Game and wad support
+- Some wads have sidedefs with a sector# of -1. Apparently, those are
+  always unused sidedefs but perhaps there is something to do about it.
+  dyst3, mm, mm2 map13,28, wads2/1kill (e2m2,6,7,8,9), wads2/adieu
+  wads2/ebola, wads2/requiem (map03,08,etc).
+- Some wads generate a flurry of messages "updating entry ''" when
+  loaded (11fortko, 1_on_1, chase21). Fix that.
+- Some working pwads are not pwads. 1sthell is an iwad.
+- Some wads have a large number of unused vertices in the middle. base,
+  phobos, 2wad/dks_e1l1, 2wad/dks_e1l3, amanda2 (no tail !), atica,
+  badblu35, dmdv (tail 76% unused 45/469), drdeath (unused 69/1382),
+  spit e1m2 unused 661/816 tail 0
+- Perhaps it would make sense to forget the directory completely when
+  it's not needed ? Each entry takes 16+4+4 = 24 bytes. Here are the
+  number of entries in the iwads' directories :
+
+  Iwad     Total entries  Level entries
+  Doom     2306  54 kB    36  9 kB
+  Doom II  2956  69 kB    32  8 kB
+  Heretic  2415  56 kB    28  7 kB
+  Hexen    4249  99 kB    32  9 kB
+
+  That's a lot. When do we use the directory ?
+  - During an editing session, to display the flats.
+  - During an editing session, to display the textures (TEXTURE1,
+    TEXTURE2, PNAMES, patches).
+  - During an editing session, to get the PLAYPAL.
+  - When loading or saving a level.
+  - At the prompt when saving or extracting a lump (not often).
+  All the levels are kept in memory all the time, even though they're
+  used only when saving and reading. The sounds, musics and graphics are
+  never unused (about 450 entries = 10 kB).
+- The message "Use F_END instead" should be displayed only once, when
+  the pwad is loaded, not each time you open an edit window.
+- Fix OpenPatchWad() so that, if a pwad contains FF_START ... FF_END
+  F_END (mm2.wad), the F_END does not replace the F_END from the iwad,
+  as this causes a spurious "this wad uses FF_END" warning.
+- icarus.wad uses F_END + FF_END. Sigh.
+- Gothic2 uses F_END but not F*_START. Therefore, the custom flats don't
+  show. FMH !
+- When a pwad contains F_START F1_START ... F3_END F_END, the F_END
+  replaces the one from the iwad and this causes Yadex to think all
+  following lumps are flats (sod.wad).
+- With hacxsw.wad, which replaces all patches and has P_START/P_END
+  labels, get a "No matching P_END for P_START in hacxsw.wad". Surely
+  the same problem as with F_END ; OpenPatchWad() uses the P_END from
+  the pwad to replace the P_END from the iwad.
+- viewpat: mm.wad and mm2.wad put patches directly in the master
+  directory, without any surrounding P_START/P_END. viewpat sees the
+  replacement patches but not the new ones of course.
+- Now that wad_read_i16() and wad_read_i32() don't abort anymore, check
+  the code that uses them.
+- Colin wants to be able to use the Final Doom iwads without having to
+  type "yadex -iwad2 /foo/bar/tnt.wad". He suggests either (1) adding a
+  new game or (2) changing the code so that "yadex -iwad2 tnt.wad" looks
+  for tnt.wad in the iwad2 directory defined in the config file.
+- Graphics: Yadex uses no COLORMAP, instead of COLORMAP 0. In practice
+  COLORMAP 0 is very close to no COLORMAP but...
+- Graphics: Yadex uses colour index IMG_TRANSP = 0 to represent
+  transparent pixels and remaps index 0 to the closest index (247 in the
+  case of Doom). Because we save in PPM format, it doesn't matter. But
+  if we wanted to save in BMP format, many pixels would have their value
+  changed, which I'd rather avoid. If Yadex used IMG_TRANSP = 255, no
+  remapping would be necessary because that index is not used in Doom,
+  Doom II, Heretic and Hexen. For Strife, it's the other way around :
+  index 255 is used quite a lot and index 0 is not.
+- Be able to edit levels with silly names like "QD2" (cf. qdoomtst.wad).
+  This implies not replacing entries in the master directory anymore !
+- When "saving as" a create'd level, NODES, SEGS, SSECTORS, REJECT,
+  BLOCKMAP and VERTEXES are not empty. Recipe : yadex: c [Return] [F3]
+  [y] [Return] beurk.wad q yadex: q $ lswad -l beurk.wad.
+- Bug: there is a small memory leak in that can be seen when repeatedly
+  loading two wads that contain the same level (E.G. while true; do echo
+  r tmp.wad; echo r 11.wad; done | yadex). I suspect the leak is in
+  ReadLevelData().
+
+Doom alpha
+- Fix wrong things definitions and add missing ones.
+- When loading a pwad with several contiguous levels, every second level
+  is discarded. See wads2.cc.
+
+Doom press release pre-beta
+- Matt says there is a separate resource file named texture2.lmp.
+
+Hexen
+- Hexen has some flats with a size of 8 kB.
+- Generate the "thing" directives by either parsing info.c or ripping
+  off the one in DETH.
+- Hexen: add linedef types and check
+
+Heretic
+- Heretic has some flats with a size of 4160. Is this why DeuTex accepts
+  64x65 flats ?
+- Most "1.666" linedefs types are wrong.
+
+Strife
+- Extract the radii from the exe.
+- Matt says sector tag 999 means "slam shut on alarm".
+- Matt wonders what RIFLB0 is and what's the difference with RIFLA0.
+- Incorporate what's only in the USS.
+
+Boom
+- convenient way of entering generalized types.
+- Decode generalized types.
+- Allow WATERMAP pseudo-texture (frankc@srv.net).
+
+XDoom
+- Write or get someone to write xdoom.ygd.
+- Check XDoom linedef types
+- Copy XDoom linedefs types to doom.ygd
+
+ZDoom
+- Allow AARRGGBB pseudo-texture ? (frankc@srv.net)
+
+EDGE
+- Abstract away extrafloor linedef types.
+- Parse DDF and RTS.
+- Function to jump to n-th extrafloor for this sector.
+
+Messages and reports
+  The reason for emitting messages :
+  - Bug (internal error, unexpected condition in the program that
+    indicates the existence of a bug somewhere)
+  - Error in the iwad (something looks fishy)
+  - Environment error (not enough memory, failure to open a file for
+    writing, failure to create a subprocess, failure to allocate X
+    resources or to connect to the X server, etc.)
+  - Informational (to inform the user on what's happening)
+  - Verbose messages (like informational, except that they are not on by
+    default and are meant as an aid to debugging)
+  - Syntax error messages
+  - Usage message
+  - Copyright message
+
+  Certain messages could be prefixed by the name of the program
+  ("yadex: "). I think this would be only useful for messages that are
+  issued while Yadex is not in interactive mode. For messages that are
+  meant to happen only in interactive mode, the prefix is a waste of
+  screen real estate.
+
+  Messages can be printed to stdout, stderr and on the window, or a
+  combination of these. Future versions of Yadex might have a GUI-only
+  interface and stdout/stderr messages might be lost, then. To print
+  messages on the window, it would be better to have a scrollable
+  message textbox at the bottom than alert boxes, that require constant
+  interaction and leave no trace.
+
+  Bug messages should come with a "THIS IS A BUG" notice and an
+  exhortation to go tell the maintainer.
+
+  If possible, the message printing function(s) should be
+  interface-independant.
+
+  There should be a smart handling of carriage returns. Instead of
+  inserting '\n' in the format string, one should be able to specify
+  whether the message should start on a new line and whether the message
+  should be followed by a newline.
+
+  There should be some handling of indent. One should be able to start
+  and end an indented block. The output routine would take care of the
+  printing of the indent whitespace.
+
+  If possible, it should be possible to write to several channels
+  (indent levels) asynchronously.
+
+Confirmation
+- Fine selection of automatic confirmations ("split linedef when
+  inserting new vertex", "split linedef when moving vertex", "merging
+  vertices", etc).
+- When moving a bunch of vertices, do not check for vertex-on-linedef
+  condition if both vertices of the linedef were part of the vertices
+  that are being moved.
+  AJA 2000-09-21: (d) when moving a large bunch of vertices or linedefs
+  that are very close together (e.g. 2 units), there often pops up a
+  message to confirm merging vertices or splitting a linedef.  (This
+  would be worse with the 1.5.0 config file which makes merges/splits
+  happen automatically).
+  I guess the solution would be making Yadex to skip checks for
+  overlapping vertex/linedef _between_ all the vertices/lines that are
+  being moved at once (i.e. only check a moving V/L against a non-moving
+  V/L).
+
+Old bugs to fix
+- When splitting and merging sectors, some of the sidedefs in the split
+  sector are given the wrong sector number.
+- When splitting a sector, sometimes get erroneous messages like
+  "vertices A and B not on the same sector" or "cannot find a closed
+  path", etc. I have already got "no sector between vertex A and vertex
+  B" ; save, quit, edit and try again : it works !
+- DOS: Let [right] work after [space] (works if no mouse driver!)
+- DOS: understand why mouse pointer moves 8 pixels at a time and fix
+  that.
+- When merging sectors, linedefs sometimes get only 1 sidedef...
+- If you do "delete linedef and merge sectors" when it's the same sector
+  on both sides of the linedef, the sector is deleted.
+- Check that all sectors are closed : chokes on pseudo sectors (s1=s2).
+  I've verified that unclosed sectors, whether single ou double sided
+  don't disturb Doom. However, some look ugly. The checking function
+  should be modified so that only ugly unclosed sectors are reported.
+- Create new sector from linedefs: should be smarter.
+
+Editing in general
+- Implement undo and redo.
+- Move cursor : jump to next object in direction ...
+- Move objects n grid steps in direction ...
+- Move objects n Grid steps in direction ...
+- Move object to nth next grid position in direction ...
+- Move object to nth next Grid position in direction ...
+- Flip info window on either side of the screen.
+- Gadget: show level with different orientations, i.e. with logical
+  north not always being at the top. And rotate the sprite images
+  accordingly.
+- Go to next/previous object in selection.
+- Renumbering objects:
+  - Renumber the selected object by either exchanging numbers with the
+    object having the target number or bumping all numbers by one. The
+    former solution has the advantage of being faster. The second
+    solution has the advantage of not disturbing the relative numbering
+    of the other objects.
+  - Make the highlighted object the lowest-numbered (highest-numbered)
+    one of all the selected objects of the same kind.
+- Bug: pasting repeatedly a large number of objects (all the linedefs of
+  Eternal MAP28, for instance) ends up triggering a segfault. Perhaps
+  we're overflowing/underflowing the objects arrays ?
+- Bug: my tests indicate that out-of-memory conditions are badly handled
+  (E.G. segfault upon switching to sector mode).
+- For very large levels, the lower limit on the zoom factor is too high
+  to allow showing the whole level.
+- Bug: for very large levels (very low zoom factors), the upper limit on
+  the grid step is too restrictive.
+- Strife's MAP29 is so much to the west (-23,000 or so) that the current
+  limit to -20,000 prevents from seeing the whole map.
+- Cut and paste between wads. at least in a limited way: insert the
+  contents of a wad at the cursor. involves renumbering all items by
+  adding the number of such items already existing. E.G. if there are
+  already 50 vertices, increment the vertex numbers in all the linedefs
+  by 50. Same thing for sidedefs numbers in linedefs, sector tags (DON'T
+  increment those that have a special meaning like 666 or 667 or those
+  above 900!). increment sector# in sidedefs too. that's all ?
+- Andy Baker wants a don't-drag toggle. I'd rather just add some initial
+  resistance.
+- For the two widest grids, display the coordinates along the edges.
+- There is something that sucks in the edit loop ; when you scroll
+  without moving the mouse, the selection box always "lags behind"
+  because its map coordinates are updated only _after_ the next screen
+  refresh.
+- Select all.
+- Reverse selection (select everything that's not selected and unselect
+  everything that's selected).
+- Edit functions : copy, cut, paste.
+- Crop (delete all unselected objects).
+- Persistent box for cropping ?
+- BD suggests sector creation à la DCK ([r] then draw box).
+- When there are several objects under the pointer, report it and give a
+  way to access any one of them. Or maybe implement planes ?
+- When doing drag-n-drop, should the snap-to-grid be applied to A.
+  relative position since started dragging B. or to the highlighted
+  object ? If A, you can't use drag-n-drop to snap-to-grid objects that
+  aren't. If B, you can't drag correctly objects that are not aligned on
+  grid.
+- Object number: the type should be "i16", not "int" (cf. SelPtr).
+- Object number: the test for "none" should not be hard-coded "< 0".
+- While dragging or drawing a selbox, prevent Del, Ins, etc. from
+  working. E.G. Del would suppress the object being dragged !
+- Add config file parameters for initial snap_to_grid and
+  lock_grid_step.
+- Scale: make it local to an edit window.
+- MadeChanges: make it local to an edit window.
+- MadeMapChanges: make it local to an edit window.
+- When saving with [F2], ".wad" should be appended automatically.
+- Save ([F2]): should not ask for the file name every time.
+- Save ([F2]): I swear I've seen the file name dialog open with
+  "nase.bak" in it !
+- Save ([F2]): should use the Save as... ([F3]) code, not duplicate it.
+- Get rid of the Level variable.
+- The file name should be a member of edit-session or level-data, not
+  retrieved by looking up the master directory.
+- A function that would be really very useful would be the possibility
+  to change the start/end vertex of a linedef. That could be done by
+  holding, say, [Alt], down and dragging the start/end until on top of
+  another vertex. When the button is released, the linedef start/end is
+  changed and the sector references of the impacted linedefs are
+  updated.
+- Displaying pointer coords; should look into using PutImageFont().
+- [Ctrl][Click]: Press button: do nothing.  Release button: select or
+  unselect IF STILL ON TOP OF OBJECT.  Thus we can use [Ctrl] + drag to
+  copy :-).
+- Dragging with [Ctrl] on duplicates ?
+- Vertex on linedef: lower tolerance when zoom factor is high.  [partly
+  done as of 1998-12-20 but still needs work].
+- Check self-consistency of level data: for each linedef, v1 and v2 must
+  be either OBJ_NO_NONE or between 0 and NumVertexes and s1 and s2 must
+  be either OBJ_NO_NONE or between 0 and NumSideDefs.
+- Goto function: takes as an argument either the centre of the level or
+  a previously set mark. Like in vi: m<mark>, '<mark>. Maybe '' to go to
+  centre ?
+- Clicking and superimposed objects: if n1 and n2 (n1 < n2) are
+  superimposed, n1 is not selected but n2 is selected and you click on
+  them, Yadex thinks you are starting a new selection because
+  is_selected (highlight) is false.
+- objects.cc: GetObjectCoords(): should use center_of_objects() instead.
+- Permanently show a 64-wide object to scale ?
+- Right-button menus: access to many different menus (no modifier,
+  [Shift], [Ctrl], [Alt], several of them).
+  - Cut, copy, paste
+  - Show properties
+  - Misc. operations
+  - Frequently used properties (toggle bit of linedef...)
+  - Change tool
+- Menus: when you move the pointer over a pulled down menu is, you can
+  highlight the objects it hides.
+- Replace "insert rectangle"/"insert polygon" by :
+  - insert pillar (nb. of sides, size)
+  - insert subsector Differences in floor/ceiling height/textures and
+    lighting level could be set by predefined styles :
+    - pedestal (floor + 48, ceiling - ...)
+    - hanging from ceiling
+    - teleporters
+- In addition of make nook/make boss,
+  - insert protruding subsector
+  - insert recessed subsector
+- Minor glitch: when a popup menu is active, the spot is still shown
+- Object info box: if the box is already drawn, don't draw it again; it
+  makes the strings flicker slightly.
+- [Alt] alone should highlight the menu bar.
+- Split linedefs and sector: if there is no sector between the linedefs,
+  they shouldn't be split.
+- Split linedefs and sector: if only one linedef is
+  selected/highlighted, assume that the other linedef is the one
+  opposite.
+- Moving/scrolling: centre view around spot under pointer (binding :
+  perhaps [Ctrl][But2]).
+- James Caldwell says that, with v1.4, if you create a polygon, delete
+  the sector inside it and try to draw a selection box around the
+  linedefs, Yadex segfaults. James was not able to give me a backtrace
+  and, apparently, no one has been able to reproduce that bug. After
+  upgrading to 1.5 and a new version of Red Hat, the problem
+  disappeared. A bug in GCC 2.96 ?
+- Linedef type/sector type/thing type selector : the current
+  implementation (cascaded menus) has certain shortcomings :
+  - No scrollbars for long lists.
+  - It's not possible to associate a bitmap to an item, which would be
+    very useful for thing types.
+  - There doesn't seem to be a good way to specify which fields are to
+    be printed, especially not dynamically. This could be useful in some
+    occasions (thing types : sprite root).
+  - There doesn't seem to be a good way to change the sorting order,
+    especially not dynamically. Still it would be nice to be able to
+    sort linedef types by either (function, trigger) or (trigger,
+    function) or (number), etc.
+  - There doesn't seem to be a good way to restrict which items are
+    shown. For example, one might wish to hide all linedef types that
+    are not available in plain Doom 1.666. Arguably, that should be done
+    by chosing the right game specification in the first place, but
+    there *might* be good reasons to do otherwise.
+  It seems that ldt/st/tt selection is an operation that calls for more
+  complex interactions than a simple list menu can do. We should
+  probably use a specialised widget, perhaps like this one :
+   _________________________________________________________________
+  |                                 _____________________________   |
+  |  Group ( ) Door                |  0 --  None               |^|  |
+  |        ( ) Door (red key)      |  1 DR  Open door          | |  |
+  |         ...                    |  2 W1  Open door (stays op| |  |
+  |        ( ) Misc                |  3 ...                    | |  |
+  |        (o) All                 |  4                        | |  |
+  |                                |  5                        | |  |
+  |  Sort  ( ) Group, desc, trig   |  6                        | |  |
+  |        ( ) Group, trig, desc   |  7                        | |  |
+  |        ( ) Desc, trig, group   |  8                        | |  |
+  |        ( ) Trig, desc, group   |  9                        | |  |
+  |        ( ) Desc, trig, number  | 10                        | |  |
+  |        ( ) Trig, desc, number  | 11                        | |  |
+  |        (o) Number              | 12                        | |  |
+  |                                | 13                        | |  |
+  |  Show  [x] Boom                | 14                        | |  |
+  |        [x] EDGE                | 15                        | |  |
+  |        [x] MBF                 | 16                        | |  |
+  |        [x] PR                  | 17                        |_|  |
+  |        [x] XDoom               |_18________________________|v|  |
+  |        [x] v1.6                |<_________________________>|    |
+  |                                            _________________    |
+  |                                           |___OK___|_Cancel_|   |
+  |_________________________________________________________________|
+
+  Note #1: how do we enter linedef types by number ?
+  Note #2: the "Show" items are not hard coded but unique values of a
+  field that does not yet exist (alternatively "from which ygd file the
+  definition comes from").
+  Note #3: instead of hard-coding "Sort" items, one could make this
+  group a collection of special widgets, one for each field. Each widget
+  has two buttons : up and down. By clicking on said button, you move
+  the widget up down the list. More flexible, but also more confusing
+  when you're not used to it. Promises to be awkward to use with the
+  keyboard.
+  Note #4: it might be useful to have two descriptions : an internal one
+  that sorts well (door open, door close) and an external one that's
+  human readable (Open door, Close door).
+- Arguably, when snap to grid is on,
+  - the pointer position shown in the info bar should honour it,
+  - the pointer position used for dragging etc. should honour it.
+
+Editing, global mode:
+- Editing properties (double-clicking or [Return]), selecting by
+  clicking and selecting with a box still care about the mode. Selection
+  in general is broken, because only the number is remembered.
+- Autosplit linedef by dragging vertex doesn't work unless in vertex
+  mode.
+- draw_map(): linedefs are still shown according to mode.
+- draw_map(): need another representation for sectors (conflicts with
+  linedefs).
+- draw_map(): always show right side of linedefs ?
+
+Editing things:
+- Thing info box:
+  - Eye candy: animate the sprites.
+  - Eye candy: show the sprites according to their angle.
+  - Numeric thing type : make it optional. Give choice of format between
+    signed decimal, unsigned decimal and hexadecimal. Default format is
+    specified by config parameter format_thing_type. Also have a key
+    binding to cycle between the three.
+  - String thing type : when unknown, use the format for numeric thing
+    type.
+  - Thing angle : when unknown, give choice between signed decimal,
+    unsigned decimal and hexadecimal.
+  - Thing flags : have an option to show the numeric value of the flags
+    field, with a format one of signed decimal, unsigned decimal and
+    hexadecimal.
+- Flip/mirror: allow user to specify whether or not things should
+  be spinned.
+- Thing properties -> type : on selecting group with 0 things, fatal
+  error PTD1.
+- Check Doom's behaviour w.r.t. negative angles.
+- On the map, if the thing has a root but no sprite by that root was
+  found, display the root ? (instead of the type)
+- On the map, show things according to their angles ?
+- On the map, switch between displaying the sprite, the type in decimal,
+  the type in hex, the root, etc.
+- Option to show both the sprite and the square. Or maybe the sprite and
+  a cross, à la WinDEU/DETH ?
+- Perhaps choose between sprite and square automatically depending on
+  zoom factor ?
+- Things: the name is sometimes too long and cut off. It looks bad.
+- Unknown things (i.e. thing numbers for which there's no record in the
+  ygd) should be displayed in red, to distinguish them from things that
+  just don't have a root.
+
+Editing vertices:
+
+Editing linedefs and sidedefs
+- Linedef type : show long name.
+- Paint linedef with colour depending on difference of floor height...
+- Show several textures at a time ?
+- Insert window/corridor/door between sectors. exactly 2 linedefs must
+  be selected and they must no belong to the same sector. select style;
+  low window, high window, small door (64x72), big door (128x128-),
+  user-defined.
+- Function: split inner sector with channel:
+
+		+---------+		+---------+
+		| +-----+ |		| +-----+ |
+		| |     | |		| |     | |
+		| |     | |	===>	| +-----+ |
+		| |     | |		| +-----+ |
+		| |     | |		| |     | |
+		| +-----+ |		| +-----+ |
+		+---------+		+---------+
+
+- Function: make plain embrasure:
+
+		---+----+---		---+----+---
+		   |    |       ===>       |----|
+		   |    |                  |    |
+
+  also "45° embrasure" and "fancy embrasure" (sides are L-shaped).
+- Nooks and bosses: add a way to specify width and depth. Maybe have
+  several predefined dimensions plus user-defined dimensions (set in the
+  config file). Maybe set textures automatically (EG DOORSTOP and
+  LITE4). Provide for shapes other than rectangle.  Difference with
+  "Make nook" is that it also splits the sector.  Maybe set
+  automatically floor and ceiling height of new sector.
+- Automatically set UTU/LTU when line becomes 2-sided ?
+- Reset linedef as double-sided (sets 2S, unsets IM, clears normal
+  texture, set upper and lower textures, possibly set UTU and LTU).
+- Frequent operations : copy upper texture -> lower texture or inverse
+  set texture. mostly on 1st sidedef set normal texture copy lower+upper
+  texture = normal texture of adjacent linedef, set lower+upper texture
+  unpegged, normaltx = -
+- Select all linedefs that in same path as the highlighted one.  This
+  can be hairy when the same vertex is shared by more than 2 sidedefs.
+  Ideas that come to mind :
+  - only single-sided linedefs,
+  - only linedefs that have as many sides as the reference linedef,
+  - called from sector mode: select all linedefs that form the boundary
+    of the sector and switch to linedef mode,
+  - only linedefs that form a chain (last (n-1) == first (n)).
+- Duplicating/copying linedefs: fix the mess. The ideal would be to
+  duplicate sidedefs, but to be also able to share them (if asked
+  explicitly). Maybe by using a modifier when copying like [Alt]...
+- Duplicating/copying linedefs: allow user to specify whether or not
+  sectors should be duplicated too.
+- Function to substitute sidedef texture.
+- Dragging linedefs is still slower than dragging vertices. But it might
+  be just because of the overhead of highlighting all those linedefs.
+- Another function often needed : "split" a vertex shared between
+  several linedefs :
+
+                    |                  |
+                  --x--     ===>     --x  x--
+                    |                     |
+
+  The way to use it could be : select one or more linedefs that have a
+  common vertex. That vertex is duplicated, moved aside a little bit (so
+  as to reduce the lengths of the linedefs and the vertex reference of
+  the concerned linedefs is changed. Instead of moving it, it could be
+  selected for dragging automatically...  Could be called "unlink
+  vertex".
+- Cut corner : must select a vertex shared by two linedefs. The linedefs
+  are shortened and the vertex is replaced by a linedef connecting the
+  two other linedefs, an forming the same angle with both of them
+  (typically, 45°)
+
+                   x---              x--
+		   |       ===>     /
+		   |               x
+		   |               |
+
+  It should be possible to set the length of the new linedef in an
+  interactive fashion. But I don't see how to do that without having a
+  modeful interface.
+- Linedef type : give choice of format between signed decimal, unsigned
+  decimal, hexadecimal. Default format is specified by config parameter
+  format_thing_type. Also have a key binding to cycle between the three.
+- Linedef tag : same thing.
+- Linedef flags : give choice between string, signed decimal, unsigned
+  decimal and hexadecimal.
+- AJA 2000-09-21: (b) the texture checker only gives you two choices
+  when it encounters missing textures: stop, or make it STARTAN3 and
+  continue.  When using some Doom tricks using missing uppers/lowers,
+  this is a pain, ideally (IMHO) there would be four options: 
+
+       Press ESC to see the object,
+       or `y' to fix the texture and continue,
+       or `A' to fix all remaining textures,
+       or any other key to leave it and continue
+
+- Look into texture alignment. Look at what's been done with DETH.
+  AJA 2000-09-21: (e) I wanted to horizontally align a bunch of lower
+  textures on some two-sided lines, but the X alignment functions only
+  work on middle textures.
+
+    This is how I would prefer it to work: well, pseudo-code would
+    explain it best:
+
+       AlignX(sidedef_t S[], int NUM)
+       {
+         int i, x_offset;
+
+         // initial x offset comes from first sidedef
+         int x_offset = S[0].x_offset;
+
+         for (i=1; i < NUM; i++)
+         {
+           // ... check if S[i] contiguous with S[i-1] ...
+
+           x_offset += LineLength(S[i-1]);
+           x_offset &= 4095;
+
+           S[i].x_offset = x_offset;
+         }
+       }
+    
+    That would collapse the 8 alignment choices into 2 (sidedef1 or
+    sidedef2).  Well, 4 if you keep the texture checking versions.
+
+    It should work fine in practice since all Doom textures are powers
+    of two.  If one wasn't, it wouldn't be drawn properly since the
+    R_GetColumn() routine in the Doom source does this:
+
+        column &= (width-1)
+    
+    Do you think this "texture-independent" version is better ?
+
+- Highlighting linedefs: the test "tag > 0" is arguable. Shouldn't it be
+  "tag != 0" ?
+- When merging superimposed 1S linedefs, the resulting 2S linedef often
+  has the middle textures the 1S linedefs had.
+- Showing linedef textures: several solutions:
+  - easiest: show raw middle texture,
+  - easy: show raw upper, middle and lower textures,
+  - hardest: show as Doom would render it, with offsets, LTU, UTU and
+    all. Scale it down so as to fit in the window that has a fixed size.
+    Optionally apply brightness. Maybe show the edge of the neighbouring
+    walls, it might help for alignment.  ISSUE: it might not be a good
+    thing to respect the length of the linedef as, for long linedefs, it
+    will force us to scale down too much.  For textures that don't
+    exist, show background with cross. For texture "-", show background
+    only. For transparent texture, background sees through. It's
+    probably better to use a special colour (like black) for background
+    as the user might want to use a bright colour for window
+    backgrounds, which wouldn't look too good with Doom's dark textures.
+- Split linedef: if pointer is somewhere on top of linedef, split it
+  there (not in the middle).
+- Split linedef: buglet: the new vertex is initially put at (0,0) and
+  MapMaxX and friends are updated accordingly. So if the centre of the
+  map is way off (0,0), the next centre-map command will appear to put
+  the map off-centre.
+- Highlighting linedefs: same problem when some of the linedefs to
+  highlight have a non-zero tag. IMO, the key of the problem is the O(2)
+  part in the highlighting of sectors. Should restructure
+  HighlightObject() and HighlightObjects(). Build a bit vector of all
+  linedefs that should be highlighted and do them all in a loop, without
+  recursion. And thus we would not highlight the same linedef more than
+  once anymore.
+- Show all linedefs that have errors in red. That includes :
+  1. bad type,
+  2. type requires a tag but its tag is set to 0,
+  3. type requires a tag but no sector uses that tag,
+  4. door type on a single-sided linedef,
+  4b. W? linedef type used on single-sided linedef,
+  5. missing texture (HOM) (though this is normal for some tricks),
+  6. tx with multi-patch columns on a double-sided linedef (medusa),
+  7. bad flag,
+  8. misaligned (bad X-offset),
+  9. superimposed linedefs.
+  10. teleport type, but the target sector has no teleport exit, or it's
+      not present at all skill levels.
+  Notes:
+  - For (3), you probably need a bit vector of tags used by at least one
+    sector. When should it be refreshed ? It's perhaps safer to do it
+    from scratch before displaying, than trying to keep track...
+  - (7) is another reason to move the definition of flags out of the
+    executable and into the .ygd.
+  - (6), (8) and (9) are not too easy.
+  - The colour of the linedef should probably be reset to normal before
+    highlighting and selecting. Having lines of many different colour is
+    just going to be confusing.
+- Check texture names: if the sidedef is not used by any linedefs, you
+  are still prompted to "press [esc] to see the object". If you do, you
+  get a "Bug: GetObjectCoords: bad sector# x" message.
+
+Editing sectors
+- Set floor height to ceiling height - headroom.
+- Set ceiling height to floor height + headroom.
+- "Change sector reference" or "substitute sector" Change sector
+  reference for all the sidedefs that reference one of the selected
+  sectors.
+- Paint sectors with colour depending on tallness, brightness,
+  texture...
+- Function to substitute sector texture.
+- Dragging sectors is still slower than dragging vertices. But it might
+  be because of the overhead incurred by highlighting all the linedefs.
+- Sectors are sometimes mistakenly considered unclosed and don't
+  highlight properly. E.G. in ss27bet2.wad, sector #66.
+  Also: I already got erroneous "sector not closed" messages. The last
+  time I remember, it was on a tiny triangular sector (base=16,
+  height=2).
+  AJA 2000-09-21: two linedefs meeting at a vertex, and the other ends
+  are very close to each other (like 2 units) causes spurious
+  Sector-not-closed messages in the consistency check.
+- A DCK-like philosophy could be used when moving sectors :
+
+	|			|
+	|  +----+	      +-+--+
+	|  |    |	==>   |    |
+	|  |    |	      |    |
+	|  +----+	      +-+--+
+	|			|
+
+- Sector type : give choice of format between signed decimal, unsigned
+  decimal, hexadecimal. Default format is specified by config parameter
+  format_thing_type. Also have a key binding to cycle between the three.
+- Sector tag : same thing.
+- Eye candy: animate flats
+- Bug: in sectors mode, [n], [p] and [<] sometimes loop over the same
+  sector forever because GoToObject() does not do quite the right thing
+  regarding subsectors. [>] is not subject to this problem because then
+  [Shift] is on. [If you're confused by this entry, look at the layout
+  for a french PC keyboard in xkeycaps.]
+- Place the sector number correctly. Account for convex sectors
+  and fractioned sectors. Avoid sloping due to an excess of
+  vertices on one side. One strategy that comes to mind is
+  placing it at the centre of the largest area (where
+  "largeness" is a compound of "surface" and "squareness").
+- Showing sector textures: optionally apply brightness.
+- Andy Baker reported than when merging linedefs, Yadex sometimes
+  deleted the wrong linedef.
+- Highlighting sectors: for a constant number of sectors to highlight,
+  gets slower as the total number of sectors increases. Might have to do
+  with the search for tagged linedefs.
+
+Keyboard interface
+- Proposition: in linedef mode, <letter><letter> gives access to
+  parameter.
+- Add macros and key bindings.
+
+Documentation
+- Update DEU 5.21 doc...
+- Document screenshot.
+- faq.html should be included in the distribution.
+- Some entries in the FAQ should also be in trouble.html and vice-versa.
+- In TODO, entries should be numbered.
+- The following should be externalized:
+  - the URL of the homepage (when it's done, update web/readme.html)
+  - the URLs of the mirrors
+  - the names of the copyright holders (contributors et al.)
+  - the name of the maintainer
+- Each file should have its own copyright statement.
+
+Unimportant :
+- If bgi= or -bgi specifies a path for the .bgi driver, handle it.
+- Search for .cfg in directory where .wad is. hm-hm...
+- Nodes: have an option to pipe the output file through BSP.
+
+Flat/sprite/texture viewer
+- Use other palettes than #0 (also when saving).
+- Use COLORMAPs (also when saving).
+- Save bug: should save entire image, not clipped. Requires implementing
+  Sticker::load (Img, int oxfs, int yofs, int width, int height). And
+  changing textures.cc so that it does not clip the width and height.
+- Save: will never be able to save all arch-vile frame under MS-DOS
+  (contain "[", "\", "]"). Use DeuTex's translation scheme ?
+- Zoom and scrollbars.
+- Add binding to toggle between SW1* and SW2*, cycle through the frames
+  of an animation. For Hexen, it's much more complicated (3-frame
+  switches...).
+- Display number of patches (and posts, and patch list...).
+- Show several pictures at a time.
+- Add a flag somewhere to allow choosing a flat/texture that's not in
+  the list.
+- Support pictures higher than 255 and textures higher than 128.
+- If the "view" command is given a lower case argument, the positionning
+  in the list of sprite names is wrong.
+
+Build:
+- Document somewhere what RELEASE does and why it's important.
+- Makefile: after changing DEFINES in the makefile, running make does
+  nothing ! (have to delete manually wads.o and sanity.o)
+- Makefile: after hacking for two days on a machine, some objects are
+  not rebuilt on another machine. Even though yadex.h has changed !
+- Should not build yadex.dep from scratch every time you type "make".
+- "make clean all" fails because clean removes obj/0 but does not create
+  it again.
+- Some configuration items are not detected by configure but by the
+  makefile. This is confusing (there's no simple rule).
+- It would be nice to automatically detect when -fpermissive is needed
+  (GCC >= 3 + "extern XSetTransientForHint" in /usr/include/X11/Xlib.h)
+- It would be nice to automatically detect where the X11 headers and
+  library are. And omit -I/usr/X11R6/include from the command line when
+  it's not needed.
+
+DOS/BGI port
+- Do more modules splitting (deu.c, ReadConfigFile, menus.c). In
+  gfx.c, move InitGfx() in a separate module.
+- Be able to handle large levels.
+- Switch to DJGPP
+- Dig *.wad...
+- Maybe compress the sidedef struct (30 B -> 12 B).
+- Try to waste less space with in-core image of wad directories.
+- Respect screen ;
+  - restore contents
+  - restore proper number of lines/columns
+- Replace putimage() by calls to display_game_image().  Implement the
+  BGI version of display_game_image().
+- Old bug: numeric keypad "." means Del even if Numlock is on.
+- Old bug: fake pointer: make it an arrow and not flickering (Ben Davies).
+
+X11 port
+- Implement -geometry and -display.
+- Add an option like in Xmame to have either a private or shared
+  colormap (by default shared, at least in map mode).
+- Look into *WMHints*()
+- When drawing the map, etc, ignore some intermediate events (for mouse
+  pointer position). Also, when several arrow key keystrokes are in the
+  input key, just count them and redraw only once.
+- Set WM hints (icon name, min size, max size, etc.).
+- Find a replacement for bioskey(0) in text mode.
+- Look into getting the status of scroll lock.
+- Handle KeymapNotify events.
+- Show cursor in input boxes and let user move it with arrows and mouse.
+- The numeric keypad does not seem to work.
+- When there is another colour-hungry app running (like Netscape), get
+  error upon freeing colours. I think Xmame has the same problem.
+- Make sure that input.c intercepts only events concerning Yadex's
+  window.
+- After a resize, pointer_x/y are not updated so the wrong object is
+  highlighted.
+- After a resize, the map is redrawn 3 TIMES !  I know why : the window
+  manager (FVWM) sends three sets of exposure events. Making drawmap()
+  and refresh in general able to do partial drawings will eliminate this
+  problem. And give better performance when moving a thing, or flipping
+  through the menus.
+- Fonts: allow several font names in the config file. The first font
+  found is used. If none is found, use the default font.
+- Fonts: be able to use variable-width fonts.
+- With font "variable", in the flat viewer, underscores are not cleared
+  properly.
+- Why do I sometimes get this when closing a window :
+    X Error of failed request:  BadAccess (attempt to access private resource
+    denied)
+    Major opcode of failed request:  88 (X_FreeColors)
+    Serial number of failed request:  503121
+    Current serial number in output stream:  503135
+  I've trapped it in colour4.cc :
+    Warning: error freeing colour <hex number> (<cause>)
+  If you can reproduce this error, mail me.
+- I've heard on comp.windows.x Mattias Engdegård say that bitmap_pad is
+  relevant. What are the constraints on it, then ?
+- Use XShm.
+- Perhaps optimize transparency :
+    pic -> img -> img(scaled) -> ximage, ximage -> pixmap, pixmap
+    pic -----------------------> ximage, ximage -> pixmap, pixmap
+- Time spent within Yadex and time spent within the X server
+- When moving sprites at large scale factor, we waste a lot of time in
+  Sprite::make_bitmap, scale_img and, above all, Sprite::make_ximage.
+  Making sprites persistent across iterations helps enormously. Do it.
+
+Unix port
+- Basenames are truncated to 8 characters. The DOS approach of fixed
+  size al_f* types does not scale on Unix. Should probably modify
+  al_fana() to use dynamically allocated buffers.
+
+Platforms/Portability
+- Solaris 7: bad X11/Xlib.h. With GCC, need -fpermissive
+  and/or  -isystem /usr/openwin/include
+- Solaris 7: don't assume that having gcc implies that cc is
+  gcc. cc might be the native compiler in which case -Wall might
+  no be appreciated.
+- Solaris 9: nanosleep() needs -lrt. Best to use usleep() ?
+
+Prompt
+- Add access to the prompt from an editing window (":" like in vi).
+- Use readline.
+- "e" command (and possibly others): warn if too many arguments.
+- "e" command: perhaps accept "e 4 2" as synonym to "e e4m2".
+
+Misc.
+- Implement several windows at once ?
+- Replace all occurrences of BLACK, WHITE, ... by logical colours.
+- Externalize occurrences of ".wad".
+- Externalize occurrences of ".bak".
+- Browse mode, as in xv and psp, to browse through a large number of
+  wads.
+- Be able to open zipped files ?
+- On ProgError(), save current data to a file named yadexcrash.wad. On
+  startup, if that file exists, propose to use it.
+- Add a handler for the SIGSEGV signal to, on segfault (SIGSEGV), save
+  current data to a file named yadexcrash.wad. On startup, if that file
+  exists, propose to use it.
+- If DOOMWADDIR exists, use it ? But overridden by yadex.cfg & -iwad
+- Texture browser : it's so slow that, even on a K6/200, some textures
+  are slow to come (AMRIBS). Should cache patches ? 1999-11-28: after
+  implementing Patch_dir, did not notice a huge improvement.
+- Parameters :
+  - colour# used to represent transparent colour when saving textures,
+  - rgb used to represent transparent colour when saving textures,
+  - rgb used to represent transparent colour when displaying textures,
+- Log file: create/update it iff the pwad file is modified.
+- Events; generalize internal events and hold refresh until all events
+  have been processed. Though autoscroll could bite me.
+- Delete all those "huge" qualifiers ; means nothing for Unix and the
+  DOS version should be compiled with -mh anyway. Update: 1999-11-25:
+  Ha! Ha! Ha! Ha! Ho! Ho! ... I was so young and naive...
+- The popup menus should get the pointer position event when there is no
+  motion event. It's an issue when, to close a submenu, you click on the
+  parent menu; until you move, the parent menu still highlights the old
+  line.
+- Popup menus: that code is brittle because the same menu_c object is
+  used for popups and pull-downs. For example, if a menu was pulled down
+  before the same menu (that was previously popped up) was undrawn,
+  weird things might happen. I don't like the idea of duplicating the
+  whole menus, though. It would be cleaner to split the menu_c class
+  into a constant part and a dynamic part but it would be a lot of work.
+- Instead of { Beep(); Notify (); }, should have a specialized function.
+- Somehow unify configuration variables and game definition variables,
+  at least so that "set" displays both. AYM 2000-07-11: mmm...
+- Palette viewer: better cursor.
+- Textures: load the texture descriptions (TEXTURE[12]) once for all
+  at startup.
+- Textures: don't abort if the TEXTURE[12] lumps have weird things in
+  them.
+- There is a way to trigger the "Callback %p did not set disp_" bug
+  message. Don't remember where. Perphaps in the texture viewer. Had to
+  do with missing patches ?
+
+    yadex: viewflat checkers
+    Yadex: Bug: Callback 0x805a770 did not set disp_
+    REPORT ALL "Bug:" MESSAGES TO THE MAINTAINER !
+
+- Certain calls to InputInteger() should use different bounds so that
+  one can enter E.G. 0xffff as well as -1.
+- InputInteger() should be objectified so that it doesn't force the
+  number back to decimal every time the user hits [Tab], [Down] and
+  friends.
+- Wad_file has too many friends.
+- Do not include so much of the Boost library in the distribution
+  archive.
+- Implement a colour translation class that remaps palette indices
+  before the Sticker stage. Used for:
+  - Doom spectres,
+  - Strife peasants, advisors, etc.
+    - peasant: PEAS beige top, green trousers
+      grey    ramp: 01-1F
+      green   ramp: 20-3F
+      beige   ramp: A0-BF
+      greyish ramp: C0-DF
+  - Doom player:
+    - player 1: green:                    no translation
+    - player 2: indigo (or is it grey ?): 70h-7Fh => 60h-6Fh
+    - player 3: brown:                    70h-7Fh => 40h-4Fh
+    - player 4: red:                      70h-7Fh => 20h-2Fh
+  In the .ygd, add a "translation-id" field to the "thing" records.
+
+To do soon
+- Finish window_to_rgbbmp()
+- Transfer rgbbmp_to_rawppm() in another file (rgbppm2.cc ?)
+- Rename rgbbmp_to_rawppm() -> _ppm(), and add a parameter to choose
+  between P3 and P6.
+- Add a parameter in the config file to choose between P3 and P6 for
+  - screenshots
+  - pictures saved
+- Test XK_*_ISO_* on SCO X11R5.
+- Test on Final Doom.
+- Add option to let Yadex tell you with which options it was compiled.
+- Fix any remaining problems that might remain in saving.
+- "create": Fix the problem with levelname being NULL in EditLoop().
+  Check [F3].
+- "create": every time you [F2], the wad name is reset to the default
+  (E.G. "map01.wad").
+- Replace Patch_dir by Lump_dir.
+
+Web
+- Announce to cola automatically.
+- Generate LSM and upload to ftp.metalab.edu.
+- Upload to ftp.cdrom.com.
+- faq.html bears the wrong version number.
+- Bcc announcements to Oliver Kraus too.
+- Add patches/
+- patches/README: on the version included with the distribution archive,
+  mention that the latest patches can be found in
+  http://www.teaser.fr/~amajorel/yadex/patches/.
+- patches/README: mention the fate of the patches (some have already
+  made in into the dev version, some will have not because I haven't
+  decided yet or haven't even looked into them and some will never make
+  it).
+- Have an index page for patches/ ready, in case the web server does not
+  support automatic indexing. Use dldir for that.
+- Should all patches in the web page be also included in the
+  distribution, and vice-versa ?
+
+
+
+----------------------------------------
+
+MISCELLANEOUS MUSINGS
+
+----------------------------------------
+
+
+COLOUR HANDLING
+[AYM 1998-11-30: don't trust this, it's partially obsolete]
+Yadex can run on "a variety of displays". We can have anything from 16
+to 16M colours. It needs to be able to handle this variability correctly
+and quickly. I have to following idea : the code uses internal colour
+numbers (ICN) to specify colours. When a part of the code needs a
+certain colour, it calls a particular function with the RGB spec of that
+colour and the function returns an ICN. Only the function knows how many
+colours are really available. The rest of the code does not have to deal
+with that.  If more colours than that are asked for, it tries to
+allocate colours anyway, possibly by approximating the required colour
+by an already existing one or even by reshuffling the palette.
+
+The colour allocation function uses an internal table which has as many
+entries as there are allocated colours. Each entry contains the RGB
+description of the colour and the corresponding external colour number.
+
+The behaviour of the colour allocation function is influenced by certain
+parameters. E.G. for X11, there is a flag that says whether the user is
+willing to have a private colormap for the Yadex window.
+
+The IRGB constants in the code need to be replaced by RGB values taken
+from the configuration file (like has been done for THINGS colours).
+
+Suggestions if it's difficult to allocate all colours :
+
+  You could try to
+  - stop other colour-hungry applications
+    that may be running (such as Mozilla)
+    and restart Yadex,
+  - restart the X server with more colours
+    (E.G. "startx -- -bpp 16"),
+  - restart Yadex with -privatecmap.
+
+
+WIDGETS
+A widget should have the following methods :
+- create:
+- destroy:
+- get_size: the size the widget would like to have
+- set_size: the size the widget got from the geometry manager
+- set_coords: the top left corner assigned by the geometry manager
+- draw: can be partial !
+- undraw: only some widgets can do that
+- set_focus: gain or lose focus
+
+The types of widgets :
+- text label
+  Attribute: text
+- button: a rectangle.
+  Attribute: text label.
+  Attribute: text label colour (grayed out ?)
+  State: depressed or normal.
+  State: would be activated by return.
+  Event: if left button is pressed on it, sinks.
+  Event: if left button had been pressed on _that_ button and is
+    released on top of it, triggers.
+  Event: if pointer moves away, returns to normal.
+  Event: if pointer comes in and left button is pressed and when it
+    was pressed, the pointer was on top of _that_ button, sinks.
+- radio buttons
+  Attribute: channel #.
+  State: on or off
+  Event: similar to button.
+- check buttons
+  Event: similar to button.
+  State: on or off
+- window
+  Attribute: title
+  Attribute: a list of widgets with placement information.
+
+
+GEOMETRY MANAGER
+The geometry manager is passed a list of widgets with placement
+information.
+Each widget is 
+Braces are groups of widgets. A group of widgets is a rectangular shell.
+By default, the group places its widgets from top to bottom and aligned
+to the left.
+A widget group can optionally be materialized by a frame and a title.
+Brace modifiers:
+- place widgets left-to-right
+- place widgets left-to-right
+- place widgets top-to-bottom
+- place widgets bottom-to-top
+Widget modifiers (override the per-group placement order):
+- "<" left-align
+- ">" right-align
+- "^" place to the top
+- "v" place to the bottom
+
+
+DRAG-AND-DROP
+When dragging a group of objects, I see two possible policies:
+1. snap position of current object
+2. snap relative displacement
+The inconvenient of (1) is that, if no object was aligned, it is difficult
+to move the group by a whole number of grid steps.
+
+
+MOVING AND DRAGGING WITH THE KEYBOARD
+From main mode:
+  [c]  move cursor
+  [d]  drag objects
+  [f]  find object
+
+Followed by displacement commands.
+Displacement command:
+  [h]  west
+  [j]  south
+  [k]  north
+  [l]  east
+  [y]  north west
+  [u]  north east
+  [b]  south west
+  [n]  south east
+Optional displacement command prefix:
+  [f]  finer (grid step /= 4)
+  [c]  coarser (grid step *= 4)
+Any other key returns to main mode.
+
+
+FASTER DISPLAY
+I think that screen refreshes could be sped up a lot by avoiding to
+clear the pixmap but instead redrawing every widget as black. It would
+involve more CPU time per pixel but it would also divide the number of
+pixels to clear by between 10 and 100, depending on the zoom factor.
+
+It would not be very complicated to add a draw_with_background_colour()
+method to edwidget_c. But, between the moment the widgets are first
+drawn and the moment they're drawn again with the background colour, the
+level data is likely to have changed. For example, a group of vertices
+might have been dragged.
+
+I could save the level data as I draw it. The parts of the data that
+need to be saved : the vertices (x,y), the linedefs (v0,v1) and the
+things (x,y,type). For a very large level (600 things, 4000 vertices,
+4000 linedefs), that's 4000 * 4 + 4000 * 4 + 600 * 6 = 35 kB. Sounds
+quite acceptable to me, especially as compared to the 800*600*3 = 1.4 MB
+of the pixmap to clear. Idea: fold vertices data (no vertices, linedef
+is defined by x0, y0, x1, y1). A bit larger, a bit faster.
+
+I could use the undo information. But redoing might make that too
+complex.  Oh, and undoing it still not implemented ;-).
+
+I could embed some sort of versioning within the level data but I
+wouldn't like to slow down access to the level data, which is critical
+in certain parts of the application.
+
+If it works well, I might even get be able to do without a pixmap :-).
+
+
+FILE SELECTION BOX
+It would be nice to have a file selection box with a small window that
+shows a preview of the level(s) and also a few indicators for textures,
+flats and other lumps.
+
+
+FUNCTIONS AND BINDINGS
+As of version 1.6, there is a number of problems:
+- There is no way to get a list of all the bindings in use. Because of
+  that, neither the user's guide nor the man page document them and the
+  [F1] online help is incomplete and often out of date. There is also no
+  way to detect conflicts (i.e. two functions having the same binding).
+- It would be nice to be able to change the bindings for a function
+  without recompiling.
+- It would be nice to be able to define aliases or macros for the
+  functions you use often.
+- Adding a new function involves redundant changes to add it in both the
+  menus and in EditorLoop().
+- MiscOperations() makes me want to laugh.
+- EditorLoop() makes me want to cry.
+- Some functions are defined inside EditorLoop().
+- There is no simple way to define bindings using a sequence of keys
+  like g? and z? in vi.
+- The mechanism used to override the selection operation is awkward.
+- There is no support for a count prefix.
+- There is no command mode as in vi so you can't script and you can't
+  add a function without assigning it a binding first.
+
+The solution:
+All actions should, as far as possible be functions. A function is a
+piece of code that acts on editing session. It's identified by its name
+(E.G. "split_sector"). It can take parameters, such a count, the working
+set, a texture name, etc.
+
+There are three ways to invoke functions :
+- through the bindings,
+- through the menus,
+- in command mode.
+
+There should be a --list-functions option to print the list of functions
+to stdout. The output of this command would be included, after some
+massaging, into the man page and users guide.
+
+Bindings: a binding is a sequence of keystrokes, a function name and
+directives which define how the parameters of the function are set.
+There should be a --list-bindings option to print the list of bindings
+to stdout. This option would be used to generated the .cfg and the doc.
+
+Keys: keys that have no corresponding character in ASCII should be
+representable with something like "[keyname]": [ctrl], [alt], [shift],
+[return], [left], [pageup], [home], [end], [f1], [tab], [backtab]. To
+what KeySyms these map should be documented. There should be a
+--list-keys option to list all those codes to stdout. FIXME: How do we
+make the difference simultaneous and disjoint keystrokes ? Or do we just
+assume that modifiers (ctrl/alt/shift) are always simultaneous and the
+rest never are ?
+
+Command mode: by typing [:], you enter command mode. This is similar to
+vi's. Any function name can be used as a command. Parameters such as
+object numbers are entered literally (E.G. ":delete_vertex 69"). It
+should be possible to use the selection and highlight, either implicitly
+(E.G. ":delete_vertex") or explicitly (E.G. ":delete_vertex $S"). There
+should be shortcuts for function names (E.G. "dv" for "delete_vertex").
+I'd like to unify the command mode and the .cfg syntax so that you can
+call function in a .cfg, that sort of stuff.
+
+Interactivity: functions should probably refrain from popping up dialog
+boxes when called from command mode (it could be script). Either the
+caller should pass a "don't-be-interactive" flag or it's the caller that
+should pop up the dialog boxes, in which case it would have to be aware
+of an awful lot of things.
+
+Arguments 1: FIXME: named arguments ? Unix-style options ? Purely
+positional ?
+
+Arguments 2: FIXME: if there are any commands that take more than one
+list, arguments must be typed (is it a list or not) and command mode
+must provide a syntax for lists, E.G.  "item1,item2,item3".
+
+Arguments 3: FIXME: cardinality checks in the caller ? (E.G. "need
+exactly two linedefs selected").
+
+Movement functions: movement commands are used in several ways:
+- to select everything between the current pointer position to where
+  destination position without actually moving the pointer,
+- to move the pointer.
+How ?
+
+Modifiers: some functions don't do anything by themselves but change the
+way the next function behaves :
+- ["] followed by a register name, causes the next cut or paste function
+  to used that register instead of the unnamed register
+- Modifiers for selection operations. By default a selection function
+  replaces the current selection. With the following modifiers, the
+  output of the function is combined with the current selection by the
+  means of a selop : [^] xor (sel = sel ^ func), [&] intersection (sel =
+  sel & func), [|] union (sel = sel | func), [~] subtraction (sel = sel
+  & ~func).
+- <count>
+- something to make the next command use a movement selection as its
+  working set (vi can afford the luxury of duplicating commands (c vs. s
+  and d vs. x, but Yadex cannot because it has too many commands).
+
+It is desirable that these modifiers be implemented as functions, so
+that they use the same binding system as everything else.
+
+A problem with modifiers is who resets the default settings ? If it's
+EditorLoop(), how does it know which functions trigger resetting and
+which don't ? If it's the functions, isn't it a bit bletcherous ? Should
+functions have to declare that they use, say, the working set and
+EditorLoop() reset the working set only after such functions ?
+
+FIXME: at the moment, certain keys are bound to several different
+functions, depending on the mode. How do we do that ? Does it make any
+sense now that global mode is in sight ?
+
+Current functions:
+- [!]		_debug_info
+- [#]		move_num
+- [%]		toggle_show_things_sprites
+- [&]		toggle_show_object_numbers
+- [']		view_centre
+- [+]		zoom_in
+- [-]		zoom_out
+- [0]..[9]	zoom_set
+- [<]		move_prev
+- [=]		zoom_in
+- [>]		move_next
+- [@]		pop up font window
+- [E]		select_linedefs_ss
+- [G]		grid_inc
+- [H]		grid_reset
+- [_]		zoom_out
+- [`]		view_centre_zoom_fit
+- [a]		pop up "Set flag"
+- [alt][a]	pop up "About"
+- [alt][i]	info_bar_toggle
+- [b]		pop up "Toggle flag"
+- [backtab]	mode_prev
+- [c]		pop up "Clear flag"
+- [ctrl][E]	^select_linedefs_ss
+- [ctrl][b]	select_linedefs_whose_sidedefs_reference_non_existant_sector
+- [ctrl][e]	^select_linedefs_nf
+- [ctrl][g]	mode_global_toggle
+- [ctrl][k]	sector_slice
+- [ctrl][l]	force_redraw
+- [ctrl][p]	pop up palette window
+- [ctrl][r]	print sidedef xref
+- [ctrl][s]	print secret sectors
+- [ctrl][t]	print tagged linedefs or sectors
+- [ctrl][u]	select linedefs with unknown type
+- [ctrl][v]	toggle snap vertex tool
+- [ctrl][x]	obj_exchange_numbers
+- [del]		obj_delete
+- [down]	scroll_down
+- [e]		select_linedefs_nf
+- [end]		scroll_down_page
+- [esc]		quit
+- [f10]		pop up "Checks"
+- [f1]		pop up "Help"
+- [f2]		save
+- [f3]		save_as
+- [f5]		pop up "Preferences"
+- [f8]		pop up "Misc. operations"
+- [f9]		pop up "Insert a standard object"
+- [g]		grid_dec
+- [h]		grid_toggle
+- [home]	scroll_up_page
+- [i]		info_box_toggle
+- [ins]		obj_insert
+- [j]		move_num
+- [l]		mode_linedefs
+- [left]	scroll_left
+- [n]		move_next
+- [o]		copy
+- [p]		move_prev
+- [pagedown]	scroll_right_page
+- [pageup]	scroll_left_page
+- [q]		quit
+- [r]		rulers_toggle
+- [return]	pop up "Properties"
+- [right]	scroll_right
+- [s]		mode_sectors
+- [shift][f1]	screenshot
+- [shift][f2]	test_entry2
+- [space]	zoom_toggle
+- [t]		mode_things
+- [tab]		mode_next
+- [up]		scroll_up
+- [v]		mode_vertices
+- [w]		linedef_split_sector_split
+- [w]		thing_spin_ccw
+- [x]		linedef_split
+- [x]		thing_spin_cw
+- [y]		snap_toggle
+- [z]		grid_lock_toggle
+- [|]		pop up colour window
+
+Possible new functions:
+- go to {start,end,middle,other end} of linedef
+- go <count> pixels toward the {start,end} of this linedef
+- go to the {next,previous} angle along this path of linedefs (how are
+  "next" and "previous" defined ? what happens if you're on a vertex
+  that's shared by several linedefs ?)
+- move {left,right,up,down} to the edge of the selection
+- go to the centre of the rectangle that contains the selection
+- go to the nearest vertex
+- go to the nearest vertex to the {north,south,east,west}
+- make sector from linedefs, adding linedefs if necessary
+- select shortest closed linedef path
+- raise or lower the {ceiling,floor} of a sector by <count> units
+- [e][space] select_clear
+- [e][~] select_invert (in same class of objects ?)
+
+Implementation: Functions are C++ functions (FIXME: what about aliases
+and macros ?). There is a global map named "function" whose key is the
+name of the function and the value a pointer on the corresponding C++
+function. FIXME: How is this map filled ? Hard coded ? Is is possible to
+insert new elements dynamically ? It should probably be forbidden to
+modify an existing element.
+
+There is a global map named "binding" whose key is the key sequence and
+whose value is a structure containing the function name and the binding
+information. FIXME: How is this map filled ? Are the default binding
+hard coded ?
+
+FIXME: what the syntax to modify the bindings from the .cfg ? A separate
+keyword (bind [shift][f9] fart \$@) or a pseudo hash
+(binding["[shift][f9]"] = fart \$@) ? The interesting feature of the
+pseudo hash is that it can be read, not just written to.
+
+Functions that modify the selection: They do not necessarily operate on
+the main selection but perhaps on a copy of it. If we want to implement
+env_push and env_pop, it is necessary to be able to dissociate the
+selection from the editing session.
+
+FIXME do we implement the selop in EditorLoop() or in the selection
+functions ? The obvious drawback of doing it in the functions is
+redundant code and more bugs. The advantage is that it permits certain
+optimisations. For example, if selop is intersect, there is no need to
+scan the objects that are not already in the selection. Is the
+performance gain worth the ugliness ? A O(1) scan is fast and if we need
+a O(2) scan (for example to get the list of linedefs tagged to a list a
+sectors), we can make it O(1) again by using a temporary table. It's
+also a more general way to improve performance ; what if the selection
+contains everything ?
+
+I'm tempted to go for the clean, easy solution (having the functions
+return a selection of their own and having EditorLoop() combine it with
+the existing list). If performance is a problem, it can be changed
+later. One thing that will not be possible with this approach, though,
+is to write a function that inserts items in the selection a certain
+places (silly example : a function that takes a list of linedefs and
+inserts after each linedef the sectors it is tagged to). But I guess we
+can do without such a feature for the time being.
+
+Combining code:
+  (*function) (old_list, new_list);
+  if (selop == replace) {
+      old_list = new_list;
+  }
+  else {
+      if (selop == intersection) {
+	  // Make bitvector new_bv from new_list
+	  for each item in old_list
+	      if not in new_bv
+		  remove it from old_list
+      }
+      else if (selop == union) {
+	  // Make bitvector old_bv from old_list
+	  for each item in new_list
+	      if not in old_bv
+		  append in to old_list
+      }
+      else if (selop == xor) {
+	  // Make bitvector new_bv from new_list
+	  for each item in old_list
+	      if in new_bv
+		  remove it from old_list and from new_bv
+	  for each item in new_list
+	      if in new_bv
+		  append it to old_list
+      }
+      else if (selop == subtraction) {
+	  // Make bitvector new_bv from new_list
+	  for each item in old_list
+	      if in new_bv
+		  remove it from old_list
+      }
+  }
+
+In any case, it should be possible for functions to modify the input
+selection because select_clear is going to be implemented as a function.
+
+There should be a way to override the selop until further notice.
+
+EditorLoop() algorithm:
+1. Get keystroke
+2. Append to buffer
+3. Is there a binding that is exactly equal to the buffer ? If yes, call
+   the corresponding function, empty the buffer and go to 1.
+4. Is there a binding of which the contents of the buffer is an initial
+   substring ? If no, beep and empty the buffer.
+5. Go to 1.
+Also accumulate count.
+
+
+AJA PATCH
+Below is a patch that implements two other things that I would've
+liked.  Firstly, being able to turn off the warning message for the
+"Swap Sidedefs" functions for lines.  I find that I often need to flip
+a line but keep the sidedefs where they were.  The patch adds a
+"blindly_swap_sidedefs" field to the config file.  Incidentally I
+found it strange that using "Add a 2nd Sidedef" onto a fresh line
+(with no sidedefs already) put it as the first, yet flipping a single
+sided line happily swaps the sidedefs, making a line with no right
+side.
+
+Secondly, the patch lets the zoom factors of the number keys be
+configurable.
+
+Cheers,
+__
+\/   Andrew Apted  <ajapted@users.sourceforge.net>
+ 
+
+===========================================================================
+
+diff -u ./src/editloop.cc.prev ./src/editloop.cc
+--- ./src/editloop.cc.prev	Tue Sep 19 16:20:03 2000
++++ ./src/editloop.cc	Tue Sep 19 17:38:52 2000
+@@ -247,6 +247,8 @@
+ OrigX = 0;
+ OrigY = 0;
+ 
++edit_zoom_init ();
++
+ if (zoom_default == 0)
+    {
+    zoom_fit (e);
+@@ -1370,7 +1372,7 @@
+       // [0], [1], ... [9]: set the zoom factor
+       else if (is.key >= '0' && is.key <= '9')
+          {
+-         int r = edit_set_zoom (&e, is.key == '0' ? 0.1 : 1.0 / dectoi(is.key));
++         int r = edit_set_zoom (&e, digit_zoom_factors[dectoi(is.key)]);
+ 	 if (r == 0)
+ 	   RedrawMap = 1;
+          }
+diff -u ./src/cfgfile.cc.prev ./src/cfgfile.cc
+--- ./src/cfgfile.cc.prev	Tue Sep 19 16:20:24 2000
++++ ./src/cfgfile.cc	Tue Sep 19 18:33:03 2000
+@@ -345,6 +345,13 @@
+   "Merge vertices after ins. vertex",
+   &insert_vertex_merge_vertices },
+ 
++{ "blindly_swap_sidedefs",
++  NULL,
++  OPT_BOOLEAN,
++  NULL,
++  "Blindly swap sidedefs on a linedef",
++  &blindly_swap_sidedefs },
++
+ { "iwad1",
+   "i1",
+   OPT_STRINGPTR,
+@@ -556,6 +563,20 @@
+   NULL,
+   "Step between zoom factors (in %)",
+   &zoom_step },
++
++{ "digit_zoom_base",
++  NULL,
++  OPT_INTEGER,
++  NULL,
++  "Base zoom factor of digit keys (in %)",
++  &digit_zoom_base },
++
++{ "digit_zoom_step",
++  NULL,
++  OPT_INTEGER,
++  NULL,
++  "Step between zoom factors of digit keys (in %)",
++  &digit_zoom_step },
+ 
+ { NULL,
+   NULL,
+diff -u ./src/yadex.cc.prev ./src/yadex.cc
+--- ./src/yadex.cc.prev	Tue Sep 19 16:21:16 2000
++++ ./src/yadex.cc	Tue Sep 19 18:33:03 2000
+@@ -109,8 +109,11 @@
+ bool      InfoShown			= true;
+ int       zoom_default			= 0;  // 0 means fit
+ int       zoom_step			= 0;  // 0 means sqrt(2)
++int       digit_zoom_base               = 100;
++int       digit_zoom_step               = 30;
+ confirm_t insert_vertex_split_linedef	= YC_ASK_ONCE;
+ confirm_t insert_vertex_merge_vertices	= YC_ASK_ONCE;
++bool      blindly_swap_sidedefs         = false;
+ const char *Iwad1			= NULL;
+ const char *Iwad2			= NULL;
+ const char *Iwad3			= NULL;
+diff -u ./src/yadex.h.prev ./src/yadex.h
+--- ./src/yadex.h.prev	Tue Sep 19 16:21:20 2000
++++ ./src/yadex.h	Tue Sep 19 18:33:03 2000
+@@ -396,8 +396,11 @@
+ extern int   idle_sleep_ms;	// Time to sleep after empty XPending()
+ extern int   zoom_default;	// Initial zoom factor for map
+ extern int   zoom_step;		// Step between zoom factors in percent
++extern int   digit_zoom_base;	// Zoom factor of `1' key, in percent
++extern int   digit_zoom_step;	// Step between digit keys, in percent 
+ extern confirm_t insert_vertex_merge_vertices;
+ extern confirm_t insert_vertex_split_linedef;
++extern bool  blindly_swap_sidedefs;
+ extern const char *Iwad1;	// Name of the Doom iwad
+ extern const char *Iwad2;	// Name of the Doom II iwad
+ extern const char *Iwad3;	// Name of the Heretic iwad
+diff -u ./src/editobj.cc.prev ./src/editobj.cc
+--- ./src/editobj.cc.prev	Tue Sep 19 18:29:40 2000
++++ ./src/editobj.cc	Tue Sep 19 18:29:53 2000
+@@ -747,6 +747,7 @@
+       if (objtype == OBJ_LINEDEFS)
+ 	 {
+ 	 if (Expert
++            || blindly_swap_sidedefs
+             || Confirm (-1, -1,
+                "Warning: the sector references are also swapped",
+                "You may get strange results if you don't know what you are doing..."))
+diff -u ./src/editzoom.cc.prev ./src/editzoom.cc
+--- ./src/editzoom.cc.prev	Tue Sep 19 17:15:54 2000
++++ ./src/editzoom.cc	Tue Sep 19 17:42:57 2000
+@@ -36,6 +36,21 @@
+ #include "gfx.h"
+ 
+ 
++double digit_zoom_factors[10];
++
++
++void edit_zoom_init ()
++{
++  int i;
++  
++  double current = digit_zoom_base / 100.0;
++  double step = (digit_zoom_step + 100.0) / 100.0;
++
++  for (i=1; i <= 10; i++, current /= step)
++    digit_zoom_factors[i % 10] = current;
++}
++
++
+ int edit_zoom_in (edit_t *e)
+ {
+   if (! e) return 1;  // Prevent compiler warning about unused .p.
+diff -u ./src/editzoom.h.prev ./src/editzoom.h
+--- ./src/editzoom.h.prev	Tue Sep 19 17:15:58 2000
++++ ./src/editzoom.h	Tue Sep 19 17:39:03 2000
+@@ -4,6 +4,17 @@
+  */
+ 
+ 
++/* zoom factors for the digit keys
++ */
++extern double digit_zoom_factors[10];
++
++
++/*
++ *      edit_zoom_init - initialise
++ */
++void edit_zoom_init (void);
++
++
+ /*
+  *	edit_zoom_in - zoom_in
+  *
+diff -u ./yadex.cfg.prev ./yadex.cfg
+--- ./yadex.cfg.prev	Tue Sep 19 16:30:47 2000
++++ ./yadex.cfg	Tue Sep 19 18:41:14 2000
+@@ -78,6 +78,11 @@
+ 
+   insert_vertex_split_linedef = yes
+ 
++# Blindly swaps the sidedefs on a linedef, i.e. without any warning
++# prompt.  Default is false.
++
++  #blindly_swap_sidedefs = false
++
+ # Is the infobar shown ? On by default.
+ 
+   #info_bar = true
+@@ -111,8 +116,8 @@
+   #default_light_level     = 144
+   #default_lower_texture   = STARTAN3
+   #default_middle_texture  = STARTAN3
+-  #default_thing           = 3004
+   #default_upper_texture   = STARTAN3
++  #default_thing           = 3004
+ 
+ # Initial zoom factor when opening a new edit window, in
+ # percent. The special value 0 causes Yadex to adjust the zoom
+@@ -127,6 +132,12 @@
+ # two (slightly above 41% increase). It's the default.
+ 
+   #zoom_step = 0
++
++# Base zoom factor and step for the digit keys, in percent.  They work
++# like zoom_default and zoom_step above, but no special values.
++
++  #digit_zoom_base = 100
++  #digit_zoom_step = 30
+ 
+ 
+ #
+
+
+AJA PATCH #2
+Hey all,
+
+One feature I've really wanted in Yadex is the ability to point to an
+area, press a key, and have all the linedefs that face into that area
+updated so that it forms a new sector.  If the lines don't have a
+sidedef on that side, it is added, otherwise the existing sidedef is
+updated.
+
+Well I've implemented it, below is the patch :-).  The key is capital
+`Z'.  I tried `S' initially but it was easy to get mixed up with the
+sector mode switch key `s'.  It hasn't gotten heavy testing yet, but
+so far so good.  One limitation is that it doesn't handle islands
+within the chosen area -- for example the pillars near the start of
+MAP01 of DOOM 2.  Oh yeah if you're in sector mode and press the 'Z'
+key while another sector is selected, that sector reference is used on
+the updated sidedefs rather than making a new sector.
+
+Cheers,
+__
+\/   Andrew Apted  <ajapted@users.sourceforge.net>
+ 
+
+diff -r -u src_aja/editloop.cc src/editloop.cc
+--- src_aja/editloop.cc	Tue Aug 15 11:14:25 2000
++++ src/editloop.cc	Wed May  9 17:19:27 2001
+@@ -2123,6 +2123,21 @@
+ 	 RedrawMap = 1;
+ 	 }
+ 
++      // [Z] Set sector on surrounding linedefs (AJA)
++      else if (is.key == 'Z' && e.pointer_in_window) 
++         {
++         if (e.obj_type == OBJ_SECTORS && e.Selected)
++            {
++            SuperSectorSelector (e.pointer_x, e.pointer_y,
++               e.Selected->objnum);
++            }
++         else
++            {
++            SuperSectorSelector (e.pointer_x, e.pointer_y, OBJ_NO_NONE);
++            }
++         RedrawMap = 1;
++         }
++
+       // [!] Debug info (not documented)
+       else if (is.key == '!')
+          {
+diff -r -u src_aja/s_misc.cc src/s_misc.cc
+--- src_aja/s_misc.cc	Mon Aug 28 07:33:51 2000
++++ src/s_misc.cc	Thu May 10 22:16:49 2001
+@@ -29,10 +29,13 @@
+ 
+ 
+ #include "yadex.h"
++#include <math.h>
++
+ #include "entry.h"
+ #include "gfx.h"
+ #include "levels.h"
+ #include "selectn.h"
++#include "dialog.h"
+ 
+ 
+ /*
+@@ -176,6 +179,342 @@
+   Sectors[cur->objnum].light = light;
+   }
+ MadeChanges = 1;
++}
++
++
++static int find_linedef_for_area (int x, int y, int& side)
++{
++   int n, m, curx;
++   int best_match = -1;
++
++   curx = 32767;  // Oh yes, one more hard-coded constant!
++
++   for (n = 0; n < NumLineDefs; n++)
++      if ((Vertices[LineDefs[n].start].y > y)
++       != (Vertices[LineDefs[n].end].y > y))
++      {
++         int lx0 = Vertices[LineDefs[n].start].x;
++         int ly0 = Vertices[LineDefs[n].start].y;
++         int lx1 = Vertices[LineDefs[n].end].x;
++         int ly1 = Vertices[LineDefs[n].end].y;
++         m = lx0 + (int) ((long) (y - ly0) * (long) (lx1 - lx0)
++                                           / (long) (ly1 - ly0));
++         if (m >= x && m < curx)
++         {
++            curx = m;
++            best_match = n;
++         }
++      }
++
++   /* now look if this linedef has a sidedef bound to one sector */
++   if (best_match < 0)
++      return OBJ_NO_NONE;
++
++   if (Vertices[LineDefs[best_match].start].y
++     > Vertices[LineDefs[best_match].end].y)
++      side = 1;
++   else
++      side = 2;
++
++   return best_match;
++}
++
++/*
++   compute the angle between lines AB and BC, going anticlockwise.
++   result is in degrees 0 - 359.  A, B and C are vertex indices.
++   -AJA- 2001-05-09
++ */
++#define DEBUG_ANGLE  0
++
++static double angle_between_linedefs (int A, int B, int C)
++{
++   int a_dx = Vertices[B].x - Vertices[A].x;
++   int a_dy = Vertices[B].y - Vertices[A].y;
++   
++   int c_dx = Vertices[B].x - Vertices[C].x;
++   int c_dy = Vertices[B].y - Vertices[C].y;
++   
++   double AB_angle = (a_dx == 0) ? (a_dy >= 0 ? 90 : -90) :
++      atan2 (a_dy, a_dx) * 180 / M_PI;
++
++   double CB_angle = (c_dx == 0) ? (c_dy >= 0 ? 90 : -90) :
++      atan2 (c_dy, c_dx) * 180 / M_PI;
++
++   double result = CB_angle - AB_angle;
++
++   if (result >= 360)
++      result -= 360;
++   
++   while (result < 0)
++      result += 360;
++
++#if (DEBUG_ANGLE)
++   fprintf(stderr, "ANGLE %1.6f  (%d,%d) -> (%d,%d) -> (%d,%d)\n",
++      result, Vertices[A].x, Vertices[A].y,
++      Vertices[B].x, Vertices[B].y, Vertices[C].x, Vertices[C].y);
++#endif
++
++   return result;
++}
++
++/*
++   follows the path clockwise from the given start line, adding each
++   line into the appropriate set.  If the path is not closed, zero is
++   returned.  
++   
++   -AJA- 2001-05-09
++ */
++#define DEBUG_PATH  0
++
++static int select_sides_in_closed_path (bitvec_c& ld_side1,
++    bitvec_c& ld_side2, int line, int side)
++{
++   int cur_vert, prev_vert, final_vert;
++   
++   if (side == 1)
++   {
++      ld_side1.set (line);
++      cur_vert = LineDefs[line].end;
++      prev_vert = final_vert = LineDefs[line].start;
++   }
++   else
++   {
++      ld_side2.set (line);
++      cur_vert = LineDefs[line].start;
++      prev_vert = final_vert = LineDefs[line].end;
++   }
++
++#if (DEBUG_PATH)
++      fprintf(stderr, "PATH: line %d  side %d  cur %d  final %d\n",
++         line, side, cur_vert, final_vert);
++#endif
++
++   while (cur_vert != final_vert)
++   {
++      int next_line = OBJ_NO_NONE;
++      int next_vert = OBJ_NO_NONE;
++      int next_side;
++      double best_angle = 999;
++
++      // Look for the next linedef in the path.  It's the linedef that
++      // uses the current vertex and is not the current one.
++
++      for (int n = 0; n < NumLineDefs; n++)
++      {
++         if (n == line)
++            continue;
++
++         int other_vert;
++         int which_side;
++
++         if (LineDefs[n].start == cur_vert)
++         {
++            other_vert = LineDefs[n].end;
++            which_side = 1;
++         }
++         else if (LineDefs[n].end == cur_vert)
++         {
++            other_vert = LineDefs[n].start;
++            which_side = 2;
++         }
++         else
++            continue;
++
++         // found adjoining linedef
++         
++         double angle = angle_between_linedefs (prev_vert, cur_vert,
++            other_vert);
++         
++         if (! is_obj (next_line) || angle < best_angle)
++         {
++            next_line = n;
++            next_vert = other_vert;
++            next_side = which_side;
++            
++            best_angle = angle;
++         }
++
++         // Continue the search
++      }
++ 
++      line = next_line;
++      side = next_side;
++
++#if (DEBUG_PATH)
++      fprintf(stderr, "PATH NEXT: line %d  side %d  vert %d  angle %1.6f\n",
++         line, side, next_vert, best_angle);
++#endif
++
++      // None ?  Path cannot be closed
++      if (! is_obj (line))
++         return 0;
++
++      // Line already seen ?  Under normal circumstances this won't
++      // happen, but it _can_ happen and indicates a non-closed
++      // structure
++      if (ld_side1.get (line) || ld_side2.get (line))
++         return 0;
++
++      if (side == 1)
++         ld_side1.set (line);
++      else
++         ld_side2.set (line);
++       
++      prev_vert = cur_vert;
++      cur_vert = next_vert;
++   }
++
++#if (DEBUG_PATH)
++      fprintf(stderr, "PATH CLOSED !\n");
++#endif
++
++   return 1;
++}
++
++/*
++   update the side on a single linedef, using the given sector
++   reference.  Will create a new sidedef if necessary.
++ */
++static void super_set_sector_on_side (int line, wad_sdn_t& side,
++   wad_sdn_t& other, int side_no, int sector)
++{
++   if (is_obj (side) && SideDefs[side].sector == sector)
++   {
++      // there was no change.
++      return;
++   }
++   
++   int must_flip = 0;
++
++   if (! is_obj (side))
++   {
++      // if we're adding a sidedef to a line that has no sides, and
++      // the sidedef would be the 2nd one, then flip the linedef.
++      // Thus we don't end up with invalid lines -- i.e. ones with a
++      // left side but no right side.
++
++      if (! is_obj (other) && side_no == 2)
++         must_flip = 1;
++
++      InsertObject (OBJ_SIDEDEFS, OBJ_NO_NONE, 0, 0);
++      side = NumSideDefs - 1;
++
++      // if we're adding a second side to the linedef, clear out some
++      // of the properties that aren't needed anymore: middle texture,
++      // two-sided flag, and impassible flag.
++      
++      if (is_obj (other))
++      {
++         strncpy (SideDefs[side].tex3,  "-", WAD_TEX_NAME);
++         strncpy (SideDefs[other].tex3, "-", WAD_TEX_NAME);
++
++         LineDefs[line].flags |=  4;  // Set the 2S bit
++         LineDefs[line].flags &= ~1;  // Clear the Im bit
++      }
++   }
++
++   SideDefs[side].sector = sector;
++   
++   if (must_flip)
++   {
++      int temp = LineDefs[line].start;
++      LineDefs[line].start = LineDefs[line].end;
++      LineDefs[line].end = temp;
++
++      temp = side; 
++      side = other; 
++      other = temp;
++   }
++
++   MadeChanges = 1;
++   MadeMapChanges = 1;
++}
++
++static int super_find_sector_model (bitvec_c& ld_side1,
++    bitvec_c& ld_side2)
++{
++   for (int line=0; line < NumLineDefs; line++)
++   {
++      int side1 = LineDefs[line].sidedef1;
++      int side2 = LineDefs[line].sidedef2;
++
++      if (ld_side1.get (line))
++         if (is_obj (side2))
++            return SideDefs[side2].sector;
++
++      if (ld_side2.get (line))
++         if (is_obj (side1))
++            return SideDefs[side1].sector;
++   }
++
++   return OBJ_NO_NONE;
++}
++
++
++/*
++   Change the closed sector at the pointer
++
++   "sector" here really means a bunch of sidedefs that all face
++   inward to the current area under the mouse cursor.  Two basic
++   operations: (a) set the sidedef sector references to a completely
++   new sector, or (b) set them to an existing sector.  This is
++   controlled by the `new_sec' parameter.
++
++   -AJA- 2001-05-08
++ */
++
++void SuperSectorSelector (int map_x, int map_y, int new_sec)
++{
++   int line, side;
++   char msg_buf[200];
++
++   line = find_linedef_for_area (map_x, map_y, side);
++
++   if (! is_obj (line))
++   {
++      Beep ();
++      sprintf (msg_buf, "Chosen area is not closed");
++      Notify (-1, -1, msg_buf, NULL);
++      return;
++   }
++
++   bitvec_c ld_side1 (NumLineDefs);
++   bitvec_c ld_side2 (NumLineDefs);
++   
++   int closed = select_sides_in_closed_path (ld_side1, ld_side2,
++      line, side);
++
++   if (! closed)
++   {
++      Beep ();
++      sprintf (msg_buf, "Area chosen is not closed");
++      Notify (-1, -1, msg_buf, NULL);
++      return;
++   }
++
++   // -AJA- FIXME: look for "islands", closed linedef paths that lie
++   // completely inside the area, i.e. not connected to the main path.
++   // Example: the two pillars at the start of MAP01 of DOOM 2.  See
++   // GetOppositeSector() and the end of SplitSector() for a possible
++   // algorithm.
++   
++   if (! is_obj (new_sec))
++   {
++      int model = super_find_sector_model (ld_side1, ld_side2);
++      InsertObject (OBJ_SECTORS, model, 0, 0);
++      new_sec = NumSectors - 1;
++   }
++   
++   for (line=0; line < NumLineDefs; line++)
++   {
++      if (ld_side1.get (line))
++         super_set_sector_on_side (line, LineDefs[line].sidedef1,
++            LineDefs[line].sidedef2, 1, new_sec);
++
++      else if (ld_side2.get (line))
++         super_set_sector_on_side (line, LineDefs[line].sidedef2,
++            LineDefs[line].sidedef1, 2, new_sec);
++   }
+ }
+ 
+ /* end of file */
+diff -r -u src_aja/yadex.h src/yadex.h
+--- src_aja/yadex.h	Wed Aug 16 07:22:40 2000
++++ src/yadex.h	Tue May  8 20:32:53 2001
+@@ -584,6 +584,7 @@
+ void DistributeSectorCeilings (SelPtr); /* SWAP! */
+ void RaiseOrLowerSectors (SelPtr obj);
+ void BrightenOrDarkenSectors (SelPtr obj);
++void SuperSectorSelector (int map_x, int map_y, int new_sec);
+ 
+ /* s_prop.cc (previously in editobj.cc) */
+ void SectorProperties (int x0, int y0, SelPtr obj);
+
+
+AJA PATCH #3
+Here is a patch that implements two features I mentioned before:
+
+  (a) the 'w' key in vertex mode doing "split sector" function.
+      It's quite handy.  (code was a doddle).
+
+  (b) the 'T' key doing property transfer from highlighted object
+      to all selected objects.
+
+Patch is against 1.5.1 (like the SuperSector one, which BTW has been
+extremely useful -- I use it all the time and wouldn't want to edit
+without it.  Plus it hasn't crashed or fouled up yet).  I've tried to
+keep both patches independent -- might cause a reject against yadex.h
+though.  Andre, if you'd rather one big patch, will do.
+
+Cheers,
+__
+\/   Andrew Apted  <ajapted@users.sourceforge.net>
+ 
+
+diff -u -r src_aja/editloop.cc src/editloop.cc
+--- src_aja/editloop.cc	Tue Aug 15 11:14:25 2000
++++ src/editloop.cc	Sun May 27 15:46:12 2001
+@@ -1853,6 +1853,17 @@
+          StretchSelBox = false;
+          }
+ 
++      // [w]: split sector between vertices
++      else if (is.key == 'w' && e.obj_type == OBJ_VERTICES
++         && e.Selected && e.Selected->next && ! e.Selected->next->next)
++         {
++         SplitSector (e.Selected->next->objnum, e.Selected->objnum);
++         ForgetSelection (&e.Selected);
++         RedrawMap = 1;
++         DragObject = false;
++         StretchSelBox = false;
++         }
++
+       // [x]: spin things 1/8 turn clockwise
+       else if (is.key == 'x' && e.obj_type == OBJ_THINGS
+          && (e.Selected || is_obj (e.highlight_obj_no)))
+@@ -2134,6 +2160,30 @@
+          {
+          show_font ();
+ 	 RedrawMap = 1;
++         }
++
++      // [T] Transfer properties to selected objects (AJA)
++      else if (is.key == 'T' && e.Selected 
++            && e.highlight_obj_no >= 0)
++         {
++         switch (e.obj_type)
++            {
++            case OBJ_SECTORS:
++               TransferSectorProperties (e.highlight_obj_no, e.Selected);
++               RedrawMap = 1;
++               break;
++            case OBJ_THINGS:
++               TransferThingProperties (e.highlight_obj_no, e.Selected);
++               RedrawMap = 1;
++               break;
++            case OBJ_LINEDEFS:
++               TransferLinedefProperties (e.highlight_obj_no, e.Selected);
++               RedrawMap = 1;
++               break;
++            default:
++               Beep ();
++               break;
++            }
+          }
+ 
+       // [|] Show colours (not documented)
+diff -u -r src_aja/l_prop.cc src/l_prop.cc
+--- src_aja/l_prop.cc	Sun Apr 30 06:37:12 2000
++++ src/l_prop.cc	Sun May 27 15:41:37 2001
+@@ -477,3 +477,37 @@
+ }
+ 
+ 
++/*
++ *   TransferLinedefProperties
++ *
++ *   Note: right now nothing is done about sidedefs.  Being able to
++ *   (intelligently) transfer sidedef properties from source line to
++ *   destination linedefs could be a useful feature -- though it is
++ *   unclear the best way to do it.  OTOH not touching sidedefs might
++ *   be useful too.
++ *
++ *   -AJA- 2001-05-27
++ */
++#define LINEDEF_FLAG_KEEP  (1 + 4)
++
++void TransferLinedefProperties (int src_linedef, SelPtr linedefs)
++{
++   SelPtr cur;
++   wad_ldflags_t src_flags = LineDefs[src_linedef].flags & ~LINEDEF_FLAG_KEEP;
++
++   for (cur=linedefs; cur; cur=cur->next)
++   {
++      if (! is_obj(cur->objnum))
++         continue;
++
++      // don't transfer certain flags
++      LineDefs[cur->objnum].flags &= LINEDEF_FLAG_KEEP;
++      LineDefs[cur->objnum].flags |= src_flags;
++
++      LineDefs[cur->objnum].type = LineDefs[src_linedef].type;
++      LineDefs[cur->objnum].tag  = LineDefs[src_linedef].tag;
++
++      MadeChanges = 1;
++   }
++}
++
+diff -u -r src_aja/s_prop.cc src/s_prop.cc
+--- src_aja/s_prop.cc	Tue Jan 11 00:40:11 2000
++++ src/s_prop.cc	Sun May 27 13:29:27 2001
+@@ -208,3 +208,32 @@
+ }
+ 
+ 
++/*
++ *   TransferSectorProperties
++ *
++ *   -AJA- 2001-05-27
++ */
++void TransferSectorProperties (int src_sector, SelPtr sectors)
++{
++   SelPtr cur;
++
++   for (cur=sectors; cur; cur=cur->next)
++   {
++      if (! is_obj(cur->objnum))
++         continue;
++
++      strncpy (Sectors[cur->objnum].floort, Sectors[src_sector].floort,
++            WAD_FLAT_NAME);
++      strncpy (Sectors[cur->objnum].ceilt, Sectors[src_sector].ceilt,
++            WAD_FLAT_NAME);
++
++      Sectors[cur->objnum].floorh  = Sectors[src_sector].floorh;
++      Sectors[cur->objnum].ceilh   = Sectors[src_sector].ceilh;
++      Sectors[cur->objnum].light   = Sectors[src_sector].light;
++      Sectors[cur->objnum].special = Sectors[src_sector].special;
++      Sectors[cur->objnum].tag     = Sectors[src_sector].tag;
++
++      MadeChanges = 1;
++   }
++}
++
+diff -u -r src_aja/t_prop.cc src/t_prop.cc
+--- src_aja/t_prop.cc	Tue Jul 25 08:46:49 2000
++++ src/t_prop.cc	Sun May 27 15:22:29 2001
+@@ -315,4 +315,30 @@
+ }
+ 
+ 
++/*
++ *   TransferThingProperties
++ *
++ *   -AJA- 2001-05-27
++ */
++void TransferThingProperties (int src_thing, SelPtr things)
++{
++   SelPtr cur;
++
++   for (cur=things; cur; cur=cur->next)
++   {
++      if (! is_obj(cur->objnum))
++         continue;
++
++      Things[cur->objnum].angle = Things[src_thing].angle;
++      Things[cur->objnum].type  = Things[src_thing].type;
++      Things[cur->objnum].when  = Things[src_thing].when;
++
++      MadeChanges = 1;
++
++      things_types++;
++      things_angles++;
++   }
++}
++
++
+ /* end of file */
+diff -u -r src_aja/yadex.h src/yadex.h
+--- src_aja/yadex.h	Wed Aug 16 07:22:40 2000
++++ src/yadex.h	Sun May 27 15:45:18 2001
+@@ -506,6 +506,7 @@
+ 
+ /* l_prop.cc (previously in editobj.cc) */
+ void LinedefProperties (int x0, int y0, SelPtr obj);
++void TransferLinedefProperties (int src_linedef, SelPtr linedefs);
+ 
+ /* l_unlink.cc */
+ void unlink_sidedef (SelPtr linedefs, int side1, int side2);
+@@ -587,6 +589,7 @@
+ 
+ /* s_prop.cc (previously in editobj.cc) */
+ void SectorProperties (int x0, int y0, SelPtr obj);
++void TransferSectorProperties (int src_sector, SelPtr sectors);
+ 
+ /* s_split.cc (previously in objects.cc) */
+ void SplitSector (int, int); /* SWAP! */
+@@ -603,6 +606,7 @@
+ /* selrect.cc */
+ /* t_prop.c (previously in editobj.c) */
+ void ThingProperties (int x0, int y0, SelPtr obj);
++void TransferThingProperties (int src_thing, SelPtr things);
+ 
+ /* v_merge.cc */
+ void DeleteVerticesJoinLineDefs (SelPtr ); /* SWAP! */
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/VERSION	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,1 @@
+1.7.0
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/atclib/al_adigits.c	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,33 @@
+/*
+ *	adigits.c
+ *	al_adigits[]
+ */
+
+
+/*
+This file is part of Atclib.
+
+Atclib is Copyright © 1995-1999 André Majorel.
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public
+License as published by the Free Software Foundation; either
+version 2 of the License, or (at your option) any later version.
+
+This library 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with this library; if not, write to the Free
+Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307, USA.
+*/
+
+
+#include "atclib.h"
+
+
+const char al_adigits[36] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/atclib/al_aerrno.c	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,33 @@
+/*
+ *	aerrno.c
+ *	al_aerrno()
+ */
+
+
+/*
+This file is part of Atclib.
+
+Atclib is Copyright © 1995-1999 André Majorel.
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public
+License as published by the Free Software Foundation; either
+version 2 of the License, or (at your option) any later version.
+
+This library 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with this library; if not, write to the Free
+Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307, USA.
+*/
+
+
+#include "atclib.h"
+
+
+int al_aerrno = 0;
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/atclib/al_astrerror.c	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,48 @@
+/*
+ *	astrer.c
+ *	al_astrerror()
+ */
+
+
+/*
+This file is part of Atclib.
+
+Atclib is Copyright © 1995-1999 André Majorel.
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public
+License as published by the Free Software Foundation; either
+version 2 of the License, or (at your option) any later version.
+
+This library 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with this library; if not, write to the Free
+Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307, USA.
+*/
+
+
+#include "atclib.h"
+
+
+const char *al_astrerror (int e)
+{
+switch (e)
+  {
+  case 0            : return "No error";
+  case AL_ABADL     : return "Invalid list";
+  case AL_AEOL      : return "EOL";
+  case AL_AINVAL    : return "Invalid argument";
+  case AL_ANOFIX    : return "Not a fixed element length list";
+  case AL_ANOMEM    : return "Not enough memory";
+  case AL_ANOVAR    : return "Not a variable element length list";
+  case AL_AOVERFLOW : return "Buffer overflow";
+  default           : return "Unknown error";
+  }
+}
+ 
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/atclib/al_fana.c	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,95 @@
+/*
+ *	al_fana.c
+ *	AYM whenever
+ */
+
+
+/*
+This file is part of Atclib.
+
+Atclib is Copyright © 1995-1999 André Majorel.
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public
+License as published by the Free Software Foundation; either
+version 2 of the License, or (at your option) any later version.
+
+This library 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with this library; if not, write to the Free
+Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307, USA.
+*/
+
+
+#include <stddef.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "atclib.h"
+
+
+void al_fana (const char *ispec,
+                    char *odrv,
+                    char *opath,
+                    char *obase,
+                    char *oext)
+{
+register int offset;
+
+/* Extract the drivespec */
+#if AL_AOS == 'd'
+if (isalpha (*ispec) && ispec[1] == ':')
+  {
+  if (odrv != NULL)
+    {
+    *odrv++ = *ispec;
+    *odrv++ = ispec[1];
+    }
+  ispec += 2;
+  }
+#endif
+if (odrv != NULL)
+  *odrv = '\0';
+
+/* Extract the path */
+if (opath != NULL)
+  *opath = '\0';
+{  /* put in offset the offset of the last path separator */
+size_t n;
+for (n = 0, offset = -1; ispec[n]; n++)
+  if (al_fisps (ispec[n]))
+    offset = n;
+}
+if (offset >= 0)
+  {
+  offset += 1;
+  if (opath != NULL)
+    strncat (opath, ispec, al_amin (offset, AL_FPATH));
+  ispec += offset;
+  }
+
+/* Extract the basename */
+if (obase != NULL)
+  *obase = '\0';
+offset = al_strOLC (ispec, '.');
+if (offset == -1)
+  offset = strlen (ispec);
+if (offset > 0 && obase != NULL)
+  strncat (obase, ispec, al_amin (offset, AL_FBASE));
+ispec += offset;
+
+/* Extract the extension */
+if (oext != NULL)
+  {
+  *oext = '\0';
+  strncat (oext, ispec, AL_FEXT);
+  }
+}
+
+/*############################ EOF - alfana.c #############################*/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/atclib/al_fnature.c	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,73 @@
+/* alfnatur.c */
+/* al_fnature() */
+/* AYM 19960917 */
+
+
+/*
+This file is part of Atclib.
+
+Atclib is Copyright © 1995-1999 André Majorel.
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public
+License as published by the Free Software Foundation; either
+version 2 of the License, or (at your option) any later version.
+
+This library 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with this library; if not, write to the Free
+Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307, USA.
+*/
+
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "atclib.h"
+
+
+/*
+!&! 3al al_fnature Returns the nature of an entry
+SYNOPSIS
+int al_fnature (const char *spec)
+
+DESCRIPTION
+Performs a stat() on the entry named spec and returns the information
+relevant to the nature of the entry.
+
+RETURN VALUE
+0  The entry or path does not exist
+1  The entry exists and is a regular file
+2  The entry exists and is a directory
+3  The entry exists and is a device
+4  The entry exists and is something else (under MS-DOS, a volume label?)
+
+BUGS
+The stat() function of MSC 6.0 does not set S_IFCHR for devices but S_IFREG
+instead. For volume labels, it says that the entry does not exist.
+Therefore, al_fnature() returns 1 for a device and 0 for a volume label.
+!&!
+*/
+
+int al_fnature (const char *spec)
+{
+struct stat statbuf;
+int r;
+
+r = stat (spec, &statbuf);
+if (r)
+  return 0;
+if (statbuf.st_mode & S_IFCHR)
+  return 3;
+if (statbuf.st_mode & S_IFDIR)
+  return 2;
+if (statbuf.st_mode & S_IFREG)
+  return 1;
+return 4;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/atclib/al_lateol.c	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,40 @@
+/*
+ *	lateol.c
+ *	al_leol()
+ */
+
+
+/*
+This file is part of Atclib.
+
+Atclib is Copyright © 1995-1999 André Majorel.
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public
+License as published by the Free Software Foundation; either
+version 2 of the License, or (at your option) any later version.
+
+This library 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with this library; if not, write to the Free
+Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307, USA.
+*/
+
+
+#define AL_AILLEGAL_ACCESS
+#include "atclib.h"
+
+
+int al_leol (al_llist_t *l)
+{
+al_lcheckmagic (l);
+if (l->first == NULL || l->ateol)
+  return AL_AEOL;
+return 0;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/atclib/al_lcount.c	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,42 @@
+/*
+ *	lcount.c
+ *	al_lcount()
+ */
+
+
+/*
+This file is part of Atclib.
+
+Atclib is Copyright © 1995-1999 André Majorel.
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public
+License as published by the Free Software Foundation; either
+version 2 of the License, or (at your option) any later version.
+
+This library 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with this library; if not, write to the Free
+Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307, USA.
+*/
+
+
+#define AL_AILLEGAL_ACCESS
+#include "atclib.h"
+
+
+long al_lcount (al_llist_t *l)
+{
+if (l == NULL || l->magic != AL_LLIST_MAGIC)
+  {
+  al_aerrno = AL_ABADL;
+  return -1;
+  }
+return l->total;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/atclib/al_lcreate.c	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,77 @@
+/*
+ *	lcreate.c
+ *	al_lcreate()
+ */
+
+
+/*
+This file is part of Atclib.
+
+Atclib is Copyright © 1995-1999 André Majorel.
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public
+License as published by the Free Software Foundation; either
+version 2 of the License, or (at your option) any later version.
+
+This library 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with this library; if not, write to the Free
+Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307, USA.
+*/
+
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <memory.h>
+
+#define AL_AILLEGAL_ACCESS
+#include "atclib.h"
+
+
+al_llist_t *al_lcreate (size_t length)
+{
+al_llist_t *l;
+
+l = malloc (sizeof (al_llist_t));
+if (l == NULL)
+  {
+  al_aerrno = AL_ANOMEM;
+  return NULL;
+  }
+l->magic   = AL_LLIST_MAGIC;
+l->length  = length;
+l->first   = NULL;
+l->current = NULL;
+l->curno   = 0;
+l->ateol   = 0;
+l->prev    = NULL;
+l->total   = 0;
+return l;
+}
+
+#ifdef OLD
+The parameter flags is used to set a few options for the table:
+- If (flags & AL_LSORT) is true:
+  This flag keeps the list "sorted" so that calls to al_lread() return
+  the elements in the right order (by default, you would get them in
+  the same order that they were written).
+  This is how it works: when you issue a write, the new element is
+  inserted in the list just before the first element that is "greater"
+  than it. Thus, the list stays sorted.
+  Elements are sorted using the comparison function (*compare)(). The
+  compare parameter is a pointer to a function that can compare two
+  elements a and b and return a negative value if a is "lesser" than b,
+  a positive value if a is "greater" than b and zero if a is "equal" to
+  b. If you pass a NULL pointer, memcmp() is used.
+  Don't use this option if you don't need it because;
+  - Each writes does an additional N/2 call to (*compare)() and follows
+    N/2 more links (N = number of elements in the list).
+  - After each write, you have to rewind before you read because the
+    order of elements keeps changing.
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/atclib/al_ldelete.c	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,68 @@
+/*
+ *	ldelete.c
+ *	al_ldelete()
+ */
+
+
+/*
+This file is part of Atclib.
+
+Atclib is Copyright © 1995-1999 André Majorel.
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public
+License as published by the Free Software Foundation; either
+version 2 of the License, or (at your option) any later version.
+
+This library 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with this library; if not, write to the Free
+Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307, USA.
+*/
+
+
+#include <stdlib.h>
+
+#define AL_AILLEGAL_ACCESS
+#include "atclib.h"
+
+
+int al_ldelete (al_llist_t *l)
+{
+al_lelt_t *elt_to_delete;
+
+al_lcheckmagic (l);
+if (l->current == NULL || l->ateol)
+  {
+  al_aerrno = AL_AEOL;
+  return AL_AEOL;
+  }
+
+elt_to_delete = l->current;
+if (l->current == l->first)
+  {
+  l->first = l->current->next;
+  l->current = l->first;
+  }
+else
+  {
+  l->prev->next = l->current->next;
+  if (l->current->next == NULL)
+    l->ateol = 1;
+  else
+    l->current = l->current->next;
+  }
+/* to help being immune from stale pointers and detect the following
+   error: al_lgetpos() al_ldelete() al_lsetpos() */
+elt_to_delete->next = AL_AINVALIDPOINTER;
+free (elt_to_delete);
+l->total--;
+
+return 0;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/atclib/al_ldiscard.c	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,54 @@
+/*
+ *	ldiscard.c
+ *	al_ldiscard()
+ */
+
+
+/*
+This file is part of Atclib.
+
+Atclib is Copyright © 1995-1999 André Majorel.
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public
+License as published by the Free Software Foundation; either
+version 2 of the License, or (at your option) any later version.
+
+This library 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with this library; if not, write to the Free
+Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307, USA.
+*/
+
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <memory.h>
+
+#define AL_AILLEGAL_ACCESS
+#include "atclib.h"
+
+
+int al_ldiscard ( al_llist_t *l )
+{
+al_lelt_t *cur, *next;
+
+al_lcheckmagic (l);
+for (cur = l->first; cur != NULL; cur = next)
+  {
+  next = cur->next;
+  /* zeroing l->magic protects us anyway but deux precautions
+     valent mieux qu'une. */
+  cur->next = AL_AINVALIDPOINTER;
+  free ( cur );
+  }
+l->magic = 0;  /* so that stale pointers can't fool us later */
+free (l);
+return 0;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/atclib/al_lgetpos.c	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,43 @@
+/*
+ *	lgetpos.c
+ *	al_lgetpos()
+ */
+
+
+/*
+This file is part of Atclib.
+
+Atclib is Copyright © 1995-1999 André Majorel.
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public
+License as published by the Free Software Foundation; either
+version 2 of the License, or (at your option) any later version.
+
+This library 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with this library; if not, write to the Free
+Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307, USA.
+*/
+
+
+#define AL_AILLEGAL_ACCESS
+#include "atclib.h"
+
+
+int al_lgetpos (al_llist_t *l, al_lpos_t *pos)
+{
+al_lcheckmagic (l);
+
+pos->current = l->current;
+pos->ateol   = l->ateol;
+pos->curno   = l->curno;
+pos->prev    = l->prev;
+return 0;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/atclib/al_linsert.c	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,63 @@
+/*
+ *	linsert.c
+ *	al_linsert()
+ */
+
+
+/*
+This file is part of Atclib.
+
+Atclib is Copyright © 1995-1999 André Majorel.
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public
+License as published by the Free Software Foundation; either
+version 2 of the License, or (at your option) any later version.
+
+This library 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with this library; if not, write to the Free
+Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307, USA.
+*/
+
+
+#include <stdlib.h>
+#include <memory.h>
+
+#define AL_AILLEGAL_ACCESS
+#include "atclib.h"
+
+
+int al_linsert (al_llist_t *l, const void *buf)
+{
+al_lelt_t *new_element;
+
+al_lcheckmagic (l);
+if (l->current == NULL || l->ateol)
+  return al_lpoke (l, buf);
+new_element = malloc (sizeof (al_lelt_t) - 1 + l->length);
+if (new_element == NULL)
+  {
+  al_aerrno = AL_ANOMEM;
+  return AL_ANOMEM;
+  }
+l->total++;
+memcpy (new_element->f.data, buf, l->length);
+
+/* update forward link to new element */
+if (l->current == l->first)
+  l->first = new_element;
+else
+  l->prev->next = new_element;
+/* update forward link from new element */
+new_element->next = l->current;
+/* update list pointer */
+l->current = new_element;
+return 0;
+}
+  
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/atclib/al_linsertl.c	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,63 @@
+/*
+ *	linsertl.c
+ *	al_linsertl()
+ */
+
+
+/*
+This file is part of Atclib.
+
+Atclib is Copyright © 1995-1999 André Majorel.
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public
+License as published by the Free Software Foundation; either
+version 2 of the License, or (at your option) any later version.
+
+This library 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with this library; if not, write to the Free
+Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307, USA.
+*/
+
+
+#include <stdlib.h>
+#include <memory.h>
+
+#define AL_AILLEGAL_ACCESS
+#include "atclib.h"
+
+
+int al_linsertl (al_llist_t *l, const void *buf, size_t length)
+{
+al_lelt_t *new_element;
+
+al_lcheckmagic (l);
+if (l->current == NULL || l->ateol)
+  return al_lpoke (l, buf);
+new_element = malloc (sizeof (al_lelt_t) - 1 + length);
+if (new_element == NULL)
+  {
+  al_aerrno = AL_ANOMEM;
+  return AL_ANOMEM;
+  }
+l->total++;
+memcpy (new_element->f.data, buf, l->length);
+
+/* update forward link to new element */
+if (l->current == l->first)
+  l->first = new_element;
+else
+  l->prev->next = new_element;
+/* update forward link from new element */
+new_element->next = l->current;
+/* update list pointer */
+l->current = new_element;
+return 0;
+}
+  
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/atclib/al_llength.c	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,51 @@
+/*
+ *	llength.c
+ *	al_llength()
+ */
+
+
+/*
+This file is part of Atclib.
+
+Atclib is Copyright © 1995-1999 André Majorel.
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public
+License as published by the Free Software Foundation; either
+version 2 of the License, or (at your option) any later version.
+
+This library 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with this library; if not, write to the Free
+Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307, USA.
+*/
+
+
+#include <stddef.h>
+
+#define AL_AILLEGAL_ACCESS
+#include "atclib.h"
+
+
+size_t al_llength (al_llist_t *l)
+{
+if (l == NULL || l->magic != AL_LLIST_MAGIC)
+  {
+  al_aerrno = AL_ABADL;
+  return 0;
+  }
+if (l->length)
+  return l->length;
+if (l->ateol || l->current == NULL)
+  {
+  al_aerrno = AL_AEOL;
+  return 0;
+  }
+return l->current->v.length;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/atclib/al_lpeek.c	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,55 @@
+/*
+ *	lpeek.c
+ *	al_lpeek()
+ */
+
+
+/*
+This file is part of Atclib.
+
+Atclib is Copyright © 1995-1999 André Majorel.
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public
+License as published by the Free Software Foundation; either
+version 2 of the License, or (at your option) any later version.
+
+This library 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with this library; if not, write to the Free
+Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307, USA.
+*/
+
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <memory.h>
+
+#define AL_AILLEGAL_ACCESS
+#include "atclib.h"
+
+
+int al_lpeek (al_llist_t *l, void *buf)
+{
+al_lcheckmagic (l);
+if (! l->length)
+  {
+  al_aerrno = AL_ANOFIX;
+  return AL_ANOFIX;
+  }
+
+if (l->current == NULL || l->ateol)
+  {
+  al_aerrno = AL_AEOL;
+  return AL_AEOL;
+  }
+memcpy (buf, l->current->f.data, l->length);
+return 0;
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/atclib/al_lpeekl.c	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,64 @@
+/*
+ *	lpeekl.c
+ *	al_lpeekl()
+ */
+
+
+/*
+This file is part of Atclib.
+
+Atclib is Copyright © 1995-1999 André Majorel.
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public
+License as published by the Free Software Foundation; either
+version 2 of the License, or (at your option) any later version.
+
+This library 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with this library; if not, write to the Free
+Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307, USA.
+*/
+
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <memory.h>
+
+#define AL_AILLEGAL_ACCESS
+#include "atclib.h"
+
+
+int al_lpeekl (al_llist_t *l, void *buf, size_t *length)
+{
+size_t maxlength;
+
+al_lcheckmagic (l);
+if (l->length)
+  {
+  al_aerrno = AL_ANOVAR;
+  return AL_ANOVAR;
+  }
+
+if (l->current == NULL || l->ateol)
+  {
+  al_aerrno = AL_AEOL;
+  return AL_AEOL;
+  }
+maxlength = *length;
+*length = l->current->v.length;
+if (*length > maxlength)
+  {
+  al_aerrno = AL_AOVERFLOW;
+  return AL_AOVERFLOW;
+  }
+memcpy (buf, l->current->v.data, *length);
+return 0;
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/atclib/al_lpoke.c	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,124 @@
+/*
+ *	lpoke.c
+ *	al_lpoke()
+ */
+
+
+/*
+This file is part of Atclib.
+
+Atclib is Copyright © 1995-1999 André Majorel.
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public
+License as published by the Free Software Foundation; either
+version 2 of the License, or (at your option) any later version.
+
+This library 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with this library; if not, write to the Free
+Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307, USA.
+*/
+
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <memory.h>
+
+#define AL_AILLEGAL_ACCESS
+#include "atclib.h"
+
+
+int al_lpoke (al_llist_t *l, const void *buf)
+{
+al_lcheckmagic (l);
+if (! l->length)
+  {
+  al_aerrno = AL_ANOFIX;
+  return AL_ANOFIX;
+  }
+
+/* have to allocate a new element */
+if (l->current == NULL || l->ateol)
+  {
+  al_lelt_t *cur;
+  cur = malloc (sizeof (al_leltfix_t) - 1 + l->length);
+  if (cur == NULL) 
+    {
+    al_aerrno = AL_ANOMEM;
+    return AL_ANOMEM;
+    }
+  l->total++;
+  if (l->current == NULL)
+    l->first = l->current = cur;
+  else  /* that is "if (l->ateol)" */
+    {
+    l->current->next = cur;
+    l->current = cur;
+    l->ateol = 0;
+    }
+  cur->next = NULL;
+  }
+
+/* do the transfer */
+memcpy (l->current->f.data, buf, l->length);
+return 0;
+}
+
+
+#ifdef SORTED
+/*
+If the list is sorted, the element is inserted before the first element
+in the list that compares higher than the new element according to
+(*l->compare)().
+If it's not, the element is simply appended to the list.
+A block large enough to hold l->eltsz bytes plus some overhead is
+allocated and l->eltsz bytes are copied from buf into it.
+*/
+{
+al_lelt_t *new;     /* new element allocated */
+
+if ( l == NULL || l->magic != AL_ABADL_MAGIC )
+  return AL_ABADL;
+
+new = malloc ( sizeof ( al_lelt_t ) + l->eltsz - 1 );
+if ( new == NULL )
+  return AL_ANOMEM;
+l->writen++;
+memcpy ( new->data, buf, l->eltsz );
+
+/* the list is sorted: search the list for the first element 'cur' that is
+"greater" than new and insert new in the list just before 'cur' */
+if ( l->flags & AL_LSORT )
+  {
+  al_lelt_t *prev, *cur;
+
+  for ( prev = NULL, cur = l->first; cur != NULL; prev = cur, cur = cur->next )
+    if ( (*l->compare) ( new->data, cur->data, l->eltsz ) < 0 )
+      break;
+  /* insert new in the list between prev and cur */
+  if ( prev != NULL )
+    prev->next = new;
+  else
+    l->first = new;
+  new->next = cur;
+  }
+
+/* the list is not sorted: just add the element at the end */
+else
+  {
+  if ( l->write != NULL )
+    l->write->next = new;
+  else
+    l->first = new;
+  new->next = NULL;
+  l->write = new;
+  }
+return 0;
+}
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/atclib/al_lpokel.c	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,91 @@
+/*
+ *	lpokel.c
+ *	al_lpokel()
+ */
+
+
+/*
+This file is part of Atclib.
+
+Atclib is Copyright © 1995-1999 André Majorel.
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public
+License as published by the Free Software Foundation; either
+version 2 of the License, or (at your option) any later version.
+
+This library 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with this library; if not, write to the Free
+Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307, USA.
+*/
+
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <memory.h>
+
+#define AL_AILLEGAL_ACCESS
+#include "atclib.h"
+
+
+int al_lpokel (al_llist_t *l, const void *buf, size_t length)
+{
+al_lcheckmagic (l);
+if (l->length)
+  {
+  al_aerrno = AL_ANOVAR;
+  return AL_ANOVAR;
+  }
+
+/* have to allocate a new element */
+if (l->current == NULL || l->ateol)
+  {
+  al_lelt_t *cur;
+  cur = malloc (sizeof (al_leltvar_t) - 1 + length);
+  if (cur == NULL) 
+    {
+    al_aerrno = AL_ANOMEM;
+    return AL_ANOMEM;
+    }
+  l->total++;
+  if (l->current == NULL)
+    l->first = l->current = cur;
+  else  /* that is "if (l->ateol)" */
+    {
+    l->current->next = cur;
+    l->current = cur;
+    l->ateol = 0;
+    }
+  cur->v.length = length;
+  cur->next = NULL;
+  }
+/* resize an already existing element */
+else if (l->current->v.length != length)
+  {
+  al_lelt_t *new_element;
+  new_element = realloc (l->current, sizeof (al_leltvar_t) - 1 + length);
+  if (new_element == NULL)
+    {
+    al_aerrno = AL_ANOMEM;
+    return AL_ANOMEM;
+    }
+  new_element->v.length = length;
+  if (l->current == l->first)
+    l->first = new_element;
+  else
+    l->prev->next = new_element;
+  l->current = new_element;
+  }
+
+/* do the transfer */
+memcpy (l->current->v.data, buf, length);
+return 0;
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/atclib/al_lptr.c	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,51 @@
+/*
+ *	lptr.c
+ *	al_lptr()
+ */
+
+
+/*
+This file is part of Atclib.
+
+Atclib is Copyright © 1995-1999 André Majorel.
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public
+License as published by the Free Software Foundation; either
+version 2 of the License, or (at your option) any later version.
+
+This library 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with this library; if not, write to the Free
+Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307, USA.
+*/
+
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <memory.h>
+
+#define AL_AILLEGAL_ACCESS
+#include "atclib.h"
+
+
+void *al_lptr (al_llist_t *l)
+{
+if (l == NULL || l->magic != AL_LLIST_MAGIC)
+  {
+  al_aerrno = AL_ABADL;
+  return NULL;
+  }
+if (l->current == NULL || l->ateol)
+  {
+  al_aerrno = AL_AEOL;
+  return NULL;
+  }
+return l->length ? l->current->f.data : l->current->v.data;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/atclib/al_lread.c	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,47 @@
+/*
+ *	lread.c
+ *	al_lread()
+ */
+
+
+/*
+This file is part of Atclib.
+
+Atclib is Copyright © 1995-1999 André Majorel.
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public
+License as published by the Free Software Foundation; either
+version 2 of the License, or (at your option) any later version.
+
+This library 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with this library; if not, write to the Free
+Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307, USA.
+*/
+
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <memory.h>
+
+#define AL_AILLEGAL_ACCESS
+#include "atclib.h"
+
+
+int al_lread (al_llist_t *l, void *buf)
+{
+int r;
+
+r = al_lpeek (l, buf);
+if (r == 0)
+  r = al_lstep (l);
+return r;
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/atclib/al_lreadl.c	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,47 @@
+/*
+ *	lreadl.c
+ *	al_lreadl()
+ */
+
+
+/*
+This file is part of Atclib.
+
+Atclib is Copyright © 1995-1999 André Majorel.
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public
+License as published by the Free Software Foundation; either
+version 2 of the License, or (at your option) any later version.
+
+This library 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with this library; if not, write to the Free
+Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307, USA.
+*/
+
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <memory.h>
+
+#define AL_AILLEGAL_ACCESS
+#include "atclib.h"
+
+
+int al_lreadl (al_llist_t *l, void *buf, size_t *length)
+{
+int r;
+
+r = al_lpeekl (l, buf, length);
+if (r == 0)
+  r = al_lstep (l);
+return r;
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/atclib/al_lrewind.c	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,47 @@
+/*
+ *	lrewind.c
+ *	al_lrewind()
+ */
+
+
+/*
+This file is part of Atclib.
+
+Atclib is Copyright © 1995-1999 André Majorel.
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public
+License as published by the Free Software Foundation; either
+version 2 of the License, or (at your option) any later version.
+
+This library 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with this library; if not, write to the Free
+Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307, USA.
+*/
+
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <memory.h>
+
+#define AL_AILLEGAL_ACCESS
+#include "atclib.h"
+
+
+int al_lrewind (al_llist_t *l)
+{
+al_lcheckmagic (l);
+l->current = l->first;
+l->ateol = 0;
+l->curno = 0;
+l->prev = NULL;
+return 0;
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/atclib/al_lseek.c	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,84 @@
+/*
+ *	lseek.c
+ *	al_lseek()
+ */
+
+
+/*
+This file is part of Atclib.
+
+Atclib is Copyright © 1995-1999 André Majorel.
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public
+License as published by the Free Software Foundation; either
+version 2 of the License, or (at your option) any later version.
+
+This library 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with this library; if not, write to the Free
+Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307, USA.
+*/
+
+
+#include <stdio.h>
+
+#define AL_AILLEGAL_ACCESS
+#include "atclib.h"
+
+
+int al_lseek (al_llist_t *l, long offset, int origin)
+{
+long from, to;
+
+al_lcheckmagic (l);
+switch (origin)
+  {
+  case SEEK_SET : from = 0; break;
+  case SEEK_CUR : from = l->curno; break;
+  case SEEK_END : from = l->total; break;
+  default       : al_aerrno = AL_AINVAL; return AL_AINVAL; break;
+  }
+to = from + offset;
+
+if (to < 0)
+  {
+  al_aerrno = AL_AINVAL;
+  return AL_AINVAL;
+  }
+if (to < l->curno)
+  {
+  al_lrewind (l);   /* Can't fail so don't check */
+  from = 0;
+  }
+if (l->first == NULL && to > 0)  /* Was "from > 0" */
+  {
+  al_aerrno = AL_AEOL;
+  return AL_AEOL;
+  }
+/* Sorry for this, but the only alternative is having a backlink pointer
+   for each element and wasting 4 B per element. */
+while (l->curno < to)
+  {
+  if (l->ateol)
+    {
+    al_aerrno = AL_AEOL;
+    return AL_AEOL;
+    } 
+  if (l->current->next == NULL)
+    l->ateol = 1;
+  else
+    {
+    l->prev = l->current;
+    l->current = l->current->next;
+    }
+  l->curno++;
+  }
+return 0;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/atclib/al_lsetpos.c	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,68 @@
+/*
+ *	lsetpos.c
+ *	al_lsetpos()
+ */
+
+
+/*
+This file is part of Atclib.
+
+Atclib is Copyright © 1995-1999 André Majorel.
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public
+License as published by the Free Software Foundation; either
+version 2 of the License, or (at your option) any later version.
+
+This library 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with this library; if not, write to the Free
+Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307, USA.
+*/
+
+
+#define AL_AILLEGAL_ACCESS
+#include "atclib.h"
+
+
+int al_lsetpos (al_llist_t *l, const al_lpos_t *pos)
+{
+al_lcheckmagic (l);
+
+/* trying to catch errors with a wide mesh net.
+   one error that will go undetected is if elements have been deleted or
+   inserted before prev. l->curno is then inconsistant with l->current */
+if (pos->curno > l->total       /* elements were deleted */
+                                /* current was deleted */
+ || pos->current != NULL && pos->current->next == AL_AINVALIDPOINTER
+                                /* prev was deleted or an element was
+                                   inserted between prev and current
+                                   or current was realloc'd */
+ || pos->prev != NULL && pos->prev->next != NULL
+                      && pos->prev->next != pos->current)
+  {
+  al_aerrno = AL_AEOL;
+  return AL_AEOL;
+  }
+
+l->current = pos->current;
+l->curno   = pos->curno;
+l->ateol   = pos->ateol;
+l->prev    = pos->prev;
+
+/* if current was at EOL and an element was added, clear ateol. BTW,
+   you see here why ateol should NOT be set when current==first==NULL */
+if (l->ateol && l->current->next != NULL)
+  {
+  l->ateol = 0;
+  l->current = l->current->next;
+  }
+
+return 0;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/atclib/al_lstep.c	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,49 @@
+/*
+ *	lstep.c
+ *	al_lstep()
+ */
+
+
+/*
+This file is part of Atclib.
+
+Atclib is Copyright © 1995-1999 André Majorel.
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public
+License as published by the Free Software Foundation; either
+version 2 of the License, or (at your option) any later version.
+
+This library 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with this library; if not, write to the Free
+Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307, USA.
+*/
+
+
+#define AL_AILLEGAL_ACCESS
+#include "atclib.h"
+
+
+int al_lstep (al_llist_t *l)
+{
+al_lcheckmagic (l);
+if (l->current == NULL || l->ateol)
+  {
+  al_aerrno = AL_AEOL;
+  return AL_AEOL;
+  }
+l->prev = l->current;
+l->curno++;
+if (l->current->next == NULL)
+  l->ateol = 1;
+else
+  l->current = l->current->next;
+return 0;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/atclib/al_ltell.c	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,42 @@
+/*
+ *	ltell.c
+ *	al_ltell()
+ */
+
+
+/*
+This file is part of Atclib.
+
+Atclib is Copyright © 1995-1999 André Majorel.
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public
+License as published by the Free Software Foundation; either
+version 2 of the License, or (at your option) any later version.
+
+This library 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with this library; if not, write to the Free
+Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307, USA.
+*/
+
+
+#define AL_AILLEGAL_ACCESS
+#include "atclib.h"
+
+
+long al_ltell (al_llist_t *l)
+{
+if (l == NULL || l->magic != AL_LLIST_MAGIC)
+  {
+  al_aerrno = AL_ABADL;
+  return -1;
+  }
+return l->curno;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/atclib/al_lwrite.c	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,45 @@
+/*
+ *	lwrite.c
+ *	al_lwrite()
+ */
+
+
+/*
+This file is part of Atclib.
+
+Atclib is Copyright © 1995-1999 André Majorel.
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public
+License as published by the Free Software Foundation; either
+version 2 of the License, or (at your option) any later version.
+
+This library 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with this library; if not, write to the Free
+Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307, USA.
+*/
+
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <memory.h>
+
+#define AL_AILLEGAL_ACCESS
+#include "atclib.h"
+
+
+int al_lwrite (al_llist_t *l, const void *buf)
+{
+int r;
+r = al_lpoke (l, buf);
+if (r == 0)
+  r = al_lstep (l);
+return r;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/atclib/al_lwritel.c	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,45 @@
+/*
+ *	lwritel.c
+ *	al_lwritel()
+ */
+
+
+/*
+This file is part of Atclib.
+
+Atclib is Copyright © 1995-1999 André Majorel.
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public
+License as published by the Free Software Foundation; either
+version 2 of the License, or (at your option) any later version.
+
+This library 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with this library; if not, write to the Free
+Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307, USA.
+*/
+
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <memory.h>
+
+#define AL_AILLEGAL_ACCESS
+#include "atclib.h"
+
+
+int al_lwritel (al_llist_t *l, const void *buf, size_t length)
+{
+int r;
+r = al_lpokel (l, buf, length);
+if (r == 0)
+  r = al_lstep (l);
+return r;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/atclib/al_sapc.c	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,45 @@
+/*
+ *	sapc.c
+ *	al_sapc
+ */
+
+
+/*
+This file is part of Atclib.
+
+Atclib is Copyright © 1995-1999 André Majorel.
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public
+License as published by the Free Software Foundation; either
+version 2 of the License, or (at your option) any later version.
+
+This library 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with this library; if not, write to the Free
+Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307, USA.
+*/
+
+
+#include <string.h>
+#include "atclib.h"
+
+
+int al_sapc (char *dest, char source, size_t maxlen)
+{
+register size_t len;
+
+len = strlen (dest);
+if (len >= maxlen)
+  return 1;
+dest[len]   = source;
+dest[len+1] = '\0';
+return 0;
+}
+
+/* eof - sapc.c */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/atclib/al_saps.c	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,42 @@
+/*
+ *	saps.c
+ *	al_saps
+ */
+
+
+/*
+This file is part of Atclib.
+
+Atclib is Copyright © 1995-1999 André Majorel.
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public
+License as published by the Free Software Foundation; either
+version 2 of the License, or (at your option) any later version.
+
+This library 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with this library; if not, write to the Free
+Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307, USA.
+*/
+
+
+#include "atclib.h"
+
+
+int al_saps (char *dest, const char *source, size_t maxlen)
+{
+for (; maxlen > 0 && *dest; maxlen--)
+  dest++;
+for (; maxlen > 0 && *source; maxlen--)
+  *dest++ = *source++;
+*dest = '\0';
+return *source;
+}
+
+/* eof - saps.c */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/atclib/al_scps.c	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,40 @@
+/*
+ *	scps.c
+ *	al_scps
+ */
+
+
+/*
+This file is part of Atclib.
+
+Atclib is Copyright © 1995-1999 André Majorel.
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public
+License as published by the Free Software Foundation; either
+version 2 of the License, or (at your option) any later version.
+
+This library 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with this library; if not, write to the Free
+Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307, USA.
+*/
+
+
+#include "atclib.h"
+
+
+int al_scps (char *dest, const char *source, size_t maxlen)
+{
+for (; maxlen > 0 && *source; maxlen--)
+  *dest++ = *source++;
+*dest = '\0';
+return *source;
+}
+
+/* eof - scps.c */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/atclib/al_scpslower.c	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,41 @@
+/*
+ *	scpslower.c
+ *	al_scpslower
+ */
+
+
+/*
+This file is part of Atclib.
+
+Atclib is Copyright © 1995-1999 André Majorel.
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public
+License as published by the Free Software Foundation; either
+version 2 of the License, or (at your option) any later version.
+
+This library 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with this library; if not, write to the Free
+Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307, USA.
+*/
+
+
+#include <ctype.h>
+#include "atclib.h"
+
+
+int al_scpslower (char *dest, const char *source, size_t maxlen)
+{
+for (; maxlen > 0 && *source; maxlen--)
+  *dest++ = tolower (*source++);
+*dest = '\0';
+return *source;
+}
+
+/* eof - scpslower.c */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/atclib/al_sdup.c	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,43 @@
+/*
+ *	sdup.c
+ *	al_sdup
+ */
+
+
+/*
+This file is part of Atclib.
+
+Atclib is Copyright © 1995-1999 André Majorel.
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public
+License as published by the Free Software Foundation; either
+version 2 of the License, or (at your option) any later version.
+
+This library 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with this library; if not, write to the Free
+Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307, USA.
+*/
+
+
+#include <stdlib.h>
+#include <string.h>
+#include "atclib.h"
+
+
+char *al_sdup (const char *str)
+{
+size_t len = strlen (str) + 1;
+char *dup = malloc (len);
+if (dup != NULL)
+  memcpy (dup, str, len);
+return dup;
+}
+
+/* eof - sdup.c */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/atclib/al_sisnum.c	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,43 @@
+/*
+ *	sisnum.c
+ *	al_sisnum
+ */
+
+
+/*
+This file is part of Atclib.
+
+Atclib is Copyright © 1995-1999 André Majorel.
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public
+License as published by the Free Software Foundation; either
+version 2 of the License, or (at your option) any later version.
+
+This library 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with this library; if not, write to the Free
+Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307, USA.
+*/
+
+
+#include <ctype.h>
+#include "atclib.h"
+
+
+int al_sisnum (const char *str)
+{
+if (! *str)
+  return 0;  /* Empty string is not considered numeric */
+while (*str)
+  if (! isdigit (*str++))
+    return 0;
+return 1;
+}
+
+/* eof - sisnum.c */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/atclib/al_strolc.c	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,47 @@
+/*
+ *	solc.c
+ *	al_strOLC
+ */
+
+
+/*
+This file is part of Atclib.
+
+Atclib is Copyright © 1995-1999 André Majorel.
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public
+License as published by the Free Software Foundation; either
+version 2 of the License, or (at your option) any later version.
+
+This library 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with this library; if not, write to the Free
+Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307, USA.
+*/
+
+
+#include "atclib.h"
+
+
+int al_strOLC (const char *str, char chr)
+{
+register int offset;
+
+for (offset = 0; *str; offset++)
+  str++;
+while (offset >= 0)
+  {
+  if (*str == chr)
+    break;
+  str--;
+  offset--;
+  }
+return offset;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/atclib/atclib.h	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,232 @@
+/*
+ *      atclib.h
+ *	An excerpt of the header for Atclib
+ */
+
+
+/*
+This file is part of Atclib.
+
+Atclib is Copyright © 1995-1999 André Majorel.
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public
+License as published by the Free Software Foundation; either
+version 2 of the License, or (at your option) any later version.
+
+This library 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with this library; if not, write to the Free
+Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307, USA.
+*/
+
+
+#if !defined(AL_AATCLIB_H)  /* To be immune from double inclusion */
+#define AL_AATCLIB_H        /* To be immune from double inclusion */
+
+/* WARNING
+You should never ever define AL_AILLEGAL_ACCESS. This macro is used
+to restrict access to information that is considered private,
+undocumented and that can be changed without notice. Only Atclib
+modules can define it, not application programs.
+*/ 
+
+#ifndef FILE
+#include <stdio.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ *	al_a*
+ *	General
+ */
+/* This is meant to be an even more invalid pointer than NULL */
+#define AL_AINVALIDPOINTER ((void *)-1)
+
+/* To size_t what INT_MAX is to int. ANSI should have provided it! */
+#define AL_ASIZE_T_MAX ((size_t)(((size_t)0)-1))
+
+/* min and max are not available everywhere */
+#define	al_amin(a,b) ((a) < (b) ? (a) : (b))
+#define	al_amax(a,b) ((a) > (b) ? (a) : (b))
+
+/* Common flags */
+#define AL_AICASE  0x0001  /* Ignore case when matching strings */
+
+typedef       char *al_as_t;   /* String */
+typedef const char *al_acs_t;  /* Constant string */
+
+/* Useful when you need a specific number of bits/bytes */
+typedef unsigned char  al_au1_t;
+typedef   signed char  al_as1_t;
+typedef unsigned short al_au2_t;
+typedef   signed short al_as2_t;
+typedef unsigned long  al_au4_t;
+typedef   signed long  al_as4_t;
+
+extern int al_aerrno;
+#define AL_ABADL      1  /* Not a valid list pointer */
+#define AL_AEOL       2  /* Attempt to read at end of list or step past it */
+#define AL_AINVAL     3  /* Invalid argument */
+#define AL_ANOFIX     4  /* Not a fixed element length list */
+#define AL_ANOMEM     5  /* Not enough memory */
+#define AL_ANOVAR     6  /* Not a variable element length list */
+#define AL_AOVERFLOW  7  /* Buffer overflow */
+al_acs_t al_astrerror (int e);
+
+extern const char al_adigits[36];  /* Contains 0-9A-Z */
+
+
+/*
+ *	al_f*
+ *	Filesystem and disks
+ */
+/* FIXME how do you port this to UNIX ? */
+#define AL_FDRV 2                       /* "<d>:" */
+#define AL_FPATH 65                     /* <64_characters>"\" */
+#define AL_FBASE 8                      /* "ABCDEFGH" */
+#define AL_FEXT 4                       /* ".IJK" + 3 characters */
+#define AL_FBE (AL_FBASE+AL_FEXT)
+                                        /* complete spec (by definition) */
+#define AL_FSPEC (AL_FDRV+AL_FPATH+AL_FBASE+AL_FEXT)
+#define AL_FPCSD '\\'                   /* Path component separator for DOS */
+#define AL_FPCSU '/'                    /* Path component separator for Unix */
+#define al_fispcsd(c) ((c)=='\\'||(c)=='/') /* Is a path component separator? */
+#define al_fispcsu(c) ((c)=='/')            /* Is a path component separator? */
+#define AL_FPS '/'
+#define al_fisps(c) ((c)=='/')
+typedef char al_fdrv_t [AL_FDRV+1 ];
+typedef char al_fpath_t[AL_FPATH+1];
+typedef char al_fbase_t[AL_FBASE+1];
+typedef char al_fext_t [AL_FEXT+1 ];
+typedef char al_fbe_t  [AL_FBE+1  ];
+typedef char al_fspec_t[AL_FSPEC+1];
+void al_fana     (al_acs_t ispec, al_as_t odrv, al_as_t opath, al_as_t obase, al_as_t oext);
+int al_fcanon    (al_acs_t strin, al_as_t strout);
+int al_fchdir    (al_acs_t path);
+int al_fnature   (al_acs_t spec);
+int al_fmakepath (al_acs_t path);
+
+
+/*
+ *	al_l*
+ *	Linked lists
+ */
+#ifdef AL_AILLEGAL_ACCESS
+enum { AL_LLIST_MAGIC = 0x18a3 };  /* Magic number for al_llist_t */
+#define al_lcheckmagic(list) \
+do\
+  if (list == NULL || list->magic != AL_LLIST_MAGIC)\
+    { al_aerrno = AL_ABADL; return AL_ABADL; }\
+while (0)
+/* FIXME: this code assumes that (union *) and (void *) have the same
+   size. I don't see why they wouldn't but I don't think this is
+   warranted by the standard. */
+typedef struct             /* One element of a fixed-length list */
+  {
+  void   *next;            /* Never used (overlaid by al_lelt_t.next) */
+  char data[1];          /* First char of data buffer */
+  } al_leltfix_t;
+
+typedef struct             /* One element of a variable-length list */
+  {
+  void   *next;            /* Never used (overlaid by al_lelt_t.next) */
+  size_t length;           /* Length of the element */
+  char data[1];          /* First char of data buffer */
+  } al_leltvar_t;
+
+typedef union al_lelt_u    /* One element of any list */
+  {
+  union al_lelt_u *next;   /* Pointer to next element in the list or NULL */
+  al_leltfix_t     f;      /* The fixed-length flavour */
+  al_leltvar_t     v;      /* The variable-length flavour */
+  } al_lelt_t;
+
+struct al_llist_s          /* One instance of this per list */
+  {
+  unsigned   magic;        /* Magic number to validate the structure */
+  size_t     length;       /* Size of an element in bytes or 0 */
+  al_lelt_t *first;        /* First element of the list (or NULL) */
+  al_lelt_t *current;      /* Current element */
+  int        ateol;        /* Current is not current but previous */
+  long       curno;        /* No. of current element */
+  al_lelt_t *prev;         /* Previous element (or NULL) */
+  long       total;        /* Total number of elements */
+  };
+
+struct al_lpos_s           /* Type used by al_lgetpos and al_lsetpos to store pointer position */
+  {
+  al_lelt_t *current;
+  int        ateol;
+  long       curno;
+  al_lelt_t *prev;
+  };
+#endif
+
+typedef struct al_llist_s al_llist_t;
+typedef struct al_lpos_s  al_lpos_t;
+
+int    al_leol   (al_llist_t *l);
+long   al_lcount   (al_llist_t *l);
+al_llist_t *al_lcreate (size_t eltsz);
+int    al_ldelete  (al_llist_t *l);
+int    al_ldiscard (al_llist_t *l);
+int    al_lgetpos  (al_llist_t *l, al_lpos_t *pos);
+int    al_linsert  (al_llist_t *l, const void *buf);
+int    al_linsertl (al_llist_t *l, const void *buf, size_t length);
+size_t al_llength  (al_llist_t *l);
+int    al_lpeek    (al_llist_t *l, void *buf);
+int    al_lpeekl   (al_llist_t *l, void *buf, size_t *length);
+int    al_lpoke    (al_llist_t *l, const void *buf);
+int    al_lpokel   (al_llist_t *l, const void *buf, size_t length);
+void  *al_lptr     (al_llist_t *l);
+int    al_lread    (al_llist_t *l, void *buf);
+int    al_lreadl   (al_llist_t *l, void *buf, size_t *length);
+int    al_lrewind  (al_llist_t *l);
+int    al_lseek    (al_llist_t *l, long offset, int origin);
+int    al_lsetpos  (al_llist_t *l, const al_lpos_t *pos);
+int    al_lstep    (al_llist_t *l);
+long   al_ltell    (al_llist_t *l);
+int    al_lwrite   (al_llist_t *l, const void *buf);
+int    al_lwritel  (al_llist_t *l, const void *buf, size_t length);
+
+
+/*
+ *	al_s*
+ *	Strings
+ */
+int    al_sapc      (al_as_t dest, char   source, size_t maxlen);
+int    al_saps      (al_as_t dest, al_acs_t source, size_t maxlen);
+int    al_sapslower (al_as_t dest, al_acs_t source, size_t maxlen);
+int    al_sapsupper (al_as_t dest, al_acs_t source, size_t maxlen);
+int    al_scpc      (al_as_t dest, char   source, size_t maxlen);
+int    al_scps      (al_as_t dest, al_acs_t source, size_t maxlen);
+int    al_scpslower (al_as_t dest, al_acs_t source, size_t maxlen);
+int    al_scpsupper (al_as_t dest, al_acs_t source, size_t maxlen);
+int    al_sbegins   (al_acs_t mainstr, al_acs_t substr);
+char  *al_sdup      (al_acs_t str);
+int    al_sends     (al_acs_t mainstr, al_acs_t substr);
+size_t al_sfirsts   (al_acs_t s1, al_acs_t s2, int flags);
+size_t al_sfirstw   (al_acs_t s1, al_acs_t s2, int flags);
+int    al_sisnum    (al_acs_t str);
+int    al_strOLC    (al_acs_t str, char chr);
+#define AL_SICASE 0x01  /* Ignore case when matching */
+#define AL_SDOS   0x02  /* Dot is special and "\" is same as "/" */
+#define AL_SLDOT  0x04  /* A leading dot "." is a special character */
+#define AL_SSLASH 0x08  /* The slash "/" is a special character */
+#define AL_SESC   0x10  /* The backslash "\" escapes "*" "?" and "[" */
+int al_swcmatch (al_acs_t pattern, al_acs_t string, int flags);
+
+#ifdef __cplusplus
+}
+#endif
+#endif  /* To be immune from double inclusion */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/boost/boost/config.hpp	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,69 @@
+//  Boost config.hpp configuration header file  ------------------------------//
+
+//  (C) Copyright Boost.org 2001. Permission to copy, use, modify, sell and
+//  distribute this software is granted provided this copyright notice appears
+//  in all copies. This software is provided "as is" without express or implied
+//  warranty, and with no claim as to its suitability for any purpose.
+
+//  See http://www.boost.org for most recent version.
+
+//  Boost config.hpp policy and rationale documentation has been moved to
+//  http://www.boost.org/libs/config
+//
+//  CAUTION: This file is intended to be completely stable -
+//           DO NOT MODIFY THIS FILE!
+//
+
+#ifndef BOOST_CONFIG_HPP
+#define BOOST_CONFIG_HPP
+
+// if we don't have a user config, then use the default location:
+#if !defined(BOOST_USER_CONFIG) && !defined(BOOST_NO_USER_CONFIG)
+#  define BOOST_USER_CONFIG <boost/config/user.hpp>
+#endif
+// include it first:
+#ifdef BOOST_USER_CONFIG
+#  include BOOST_USER_CONFIG
+#endif
+
+// if we don't have a compiler config set, try and find one:
+#if !defined(BOOST_COMPILER_CONFIG) && !defined(BOOST_NO_COMPILER_CONFIG) && !defined(BOOST_NO_CONFIG)
+#  include <boost/config/select_compiler_config.hpp>
+#endif
+// if we don't have a std library config set, try and find one:
+#if !defined(BOOST_STDLIB_CONFIG) && !defined(BOOST_NO_STDLIB_CONFIG) && !defined(BOOST_NO_CONFIG)
+#  include <boost/config/select_stdlib_config.hpp>
+#endif
+// if we don't have a platform config set, try and find one:
+#if !defined(BOOST_PLATFORM_CONFIG) && !defined(BOOST_NO_PLATFORM_CONFIG) && !defined(BOOST_NO_CONFIG)
+#  include <boost/config/select_platform_config.hpp>
+#endif
+
+
+// if we have a compiler config, include it now:
+#ifdef BOOST_COMPILER_CONFIG
+#  include BOOST_COMPILER_CONFIG
+#endif
+// if we have a std library config, include it now:
+#ifdef BOOST_STDLIB_CONFIG
+#  include BOOST_STDLIB_CONFIG
+#endif
+// if we have a platform config, include it now:
+#ifdef BOOST_PLATFORM_CONFIG
+#  include BOOST_PLATFORM_CONFIG
+#endif
+
+// get config suffix code:
+#include <boost/config/suffix.hpp>
+
+#endif  // BOOST_CONFIG_HPP
+
+
+
+
+
+
+
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/boost/boost/config/compiler/borland.hpp	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,55 @@
+//  (C) Copyright Boost.org 2001. Permission to copy, use, modify, sell and
+//  distribute this software is granted provided this copyright notice appears
+//  in all copies. This software is provided "as is" without express or implied
+//  warranty, and with no claim as to its suitability for any purpose.
+
+//  See http://www.boost.org for most recent version.
+
+//  Borland C++ compiler setup:
+
+#   if __BORLANDC__ <= 0x0550
+// Borland C++ Builder 4 and 5:
+#     define BOOST_NO_MEMBER_TEMPLATE_FRIENDS
+#     if __BORLANDC__ == 0x0550
+// Borland C++ Builder 5, command-line compiler 5.5:
+#       define BOOST_NO_OPERATORS_IN_NAMESPACE
+#     endif
+#   endif
+
+#if (__BORLANDC__ >= 0x550)
+// <climits> is partly broken, some macos define symbols that are really in
+// namespace std, so you end up having to use illegal constructs like
+// std::DBL_MAX, as a fix we'll just include float.h and have done with:
+#include <float.h>
+#endif
+
+// Version 5.51:
+#if (__BORLANDC__ <= 0x551) || !defined(BOOST_STRICT_CONFIG)
+#  define BOOST_NO_CV_SPECIALIZATIONS
+#  define BOOST_NO_CV_VOID_SPECIALIZATIONS
+#  define BOOST_NO_INTEGRAL_INT64_T
+#  define BOOST_NO_PRIVATE_IN_AGGREGATE
+#  define BOOST_NO_DEPENDENT_NESTED_DERIVATIONS
+#  define BOOST_NO_SWPRINTF
+#  define BOOST_NO_USING_TEMPLATE
+#endif
+
+#define BOOST_COMPILER "Borland C++ version " BOOST_STRINGIZE(__BORLANDC__)
+
+//
+// versions check:
+// we don't support Borland prior to version 5.4:
+#if __BORLANDC__ < 0x540
+#  error "Compiler not supported or configured - please reconfigure"
+#endif
+//
+// last known and checked version is 5.51:
+#if (__BORLANDC__ > 0x551)
+#  if defined(BOOST_ASSERT_CONFIG)
+#     error "Unknown compiler version - please run the configure tests and report the results"
+#  else
+#     pragma message( "Unknown compiler version - please run the configure tests and report the results")
+#  endif
+#endif
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/boost/boost/config/compiler/comeau.hpp	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,38 @@
+//  (C) Copyright Boost.org 2001. Permission to copy, use, modify, sell and
+//  distribute this software is granted provided this copyright notice appears
+//  in all copies. This software is provided "as is" without express or implied
+//  warranty, and with no claim as to its suitability for any purpose.
+
+//  See http://www.boost.org for most recent version.
+
+//  Comeau C++ compiler setup:
+
+#include "boost/config/compiler/common_edg.hpp"
+
+#if (__COMO_VERSION__ <= 4245) || !defined(BOOST_STRICT_CONFIG)
+#  define BOOST_FUNCTION_USE_VIRTUAL_FUNCTIONS
+#  if defined(_MSC_VER) && _MSC_VER <= 1300
+#     define BOOST_NO_STDC_NAMESPACE
+#     define BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP
+#     define BOOST_NO_SWPRINTF
+#  endif
+#endif
+
+#define BOOST_COMPILER "Comeau compiler version " BOOST_STRINGIZE(__COMO_VERSION__)
+
+//
+// versions check:
+// we don't know Comeau prior to version 4245:
+#if __COMO_VERSION__ < 4245
+#  error "Compiler not configured - please reconfigure"
+#endif
+//
+// last known and checked version is 4245:
+#if (__COMO_VERSION__ > 4245)
+#  if defined(BOOST_ASSERT_CONFIG)
+#     error "Unknown compiler version - please run the configure tests and report the results"
+#  endif
+#endif
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/boost/boost/config/compiler/common_edg.hpp	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,25 @@
+//  (C) Copyright Boost.org 2001. Permission to copy, use, modify, sell and
+//  distribute this software is granted provided this copyright notice appears
+//  in all copies. This software is provided "as is" without express or implied
+//  warranty, and with no claim as to its suitability for any purpose.
+
+//  See http://www.boost.org for most recent version.
+
+//
+// Options common to all edg based compilers.
+//
+// This is included from within the individual compiler mini-configs.
+
+#ifndef __EDG_VERSION__
+#  error This file requires that __EDG_VERSION__ be defined.
+#endif
+
+#if (__EDG_VERSION__ <= 238)
+#   define BOOST_NO_VOID_RETURNS
+#endif
+
+#if (__EDG_VERSION__ <= 241) && !defined(BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP)
+#   define BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP
+#endif
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/boost/boost/config/compiler/compaq_cxx.hpp	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,18 @@
+//  (C) Copyright Boost.org 2001. Permission to copy, use, modify, sell and
+//  distribute this software is granted provided this copyright notice appears
+//  in all copies. This software is provided "as is" without express or implied
+//  warranty, and with no claim as to its suitability for any purpose.
+
+//  See http://www.boost.org for most recent version.
+
+//  Dec Alpha True64 C++ compiler setup:
+
+#define BOOST_COMPILER "Dec Alpha True64 " BOOST_STRINGIZE(__DECCXX_VER)
+
+#include "boost/config/compiler/common_edg.hpp"
+
+//
+// versions check:
+// Nothing to do here?
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/boost/boost/config/compiler/gcc.hpp	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,54 @@
+//  (C) Copyright Boost.org 2001. Permission to copy, use, modify, sell and
+//  distribute this software is granted provided this copyright notice appears
+//  in all copies. This software is provided "as is" without express or implied
+//  warranty, and with no claim as to its suitability for any purpose.
+
+//  See http://www.boost.org for most recent version.
+
+//  GNU C++ compiler setup:
+
+#   if __GNUC__ == 2 && __GNUC_MINOR__ == 91
+       // egcs 1.1 won't parse smart_ptr.hpp without this:
+#      define BOOST_NO_AUTO_PTR
+#   endif
+#   if __GNUC__ == 2 && __GNUC_MINOR__ < 95
+      //
+      // Prior to gcc 2.95 member templates only partly
+      // work - define BOOST_MSVC6_MEMBER_TEMPLATES
+      // instead since inline member templates mostly work.
+      //
+#     define BOOST_NO_MEMBER_TEMPLATES
+#     if __GNUC_MINOR__ >= 9
+#       define BOOST_MSVC6_MEMBER_TEMPLATES
+#     endif
+#   endif
+
+#   if __GNUC__ == 2 && __GNUC_MINOR__ <= 97
+#     define BOOST_NO_MEMBER_TEMPLATE_FRIENDS
+#     define BOOST_NO_OPERATORS_IN_NAMESPACE
+#   endif
+
+//
+// Threading support:
+// Turn this on unconditionally here, it will get turned off again later
+// if no threading API is detected.
+//
+#define BOOST_HAS_THREADS
+
+#define BOOST_COMPILER "GNU C++ version " BOOST_STRINGIZE(__GNUC__) "." BOOST_STRINGIZE(__GNUC_MINOR__)
+
+//
+// versions check:
+// we don't know gcc prior to version 2.90:
+#if (__GNUC__ == 2) && (__GNUC_MINOR__ < 90)
+#  error "Compiler not configured - please reconfigure"
+#endif
+//
+// last known and checked version is 3.0:
+#if (__GNUC__ > 3) || ((__GNUC__ == 3) && (__GNUC_MINOR__ > 0))
+#  if defined(BOOST_ASSERT_CONFIG)
+#     error "Unknown compiler version - please run the configure tests and report the results"
+#  else
+#     warning "Unknown compiler version - please run the configure tests and report the results"
+#  endif
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/boost/boost/config/compiler/greenhills.hpp	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,27 @@
+//  (C) Copyright Boost.org 2001. Permission to copy, use, modify, sell and
+//  distribute this software is granted provided this copyright notice appears
+//  in all copies. This software is provided "as is" without express or implied
+//  warranty, and with no claim as to its suitability for any purpose.
+
+//  See http://www.boost.org for most recent version.
+
+//  Greenhills C++ compiler setup:
+
+#define BOOST_COMPILER "Greenhills C++ version " BOOST_STRINGIZE(__ghs)
+
+#include "boost/config/compiler/common_edg.hpp"
+
+//
+// versions check:
+// we don't support Greenhills prior to version 0:
+#if __ghs < 0
+#  error "Compiler not supported or configured - please reconfigure"
+#endif
+//
+// last known and checked version is 0:
+#if (__ghs > 0)
+#  if defined(BOOST_ASSERT_CONFIG)
+#     error "Unknown compiler version - please run the configure tests and report the results"
+#  endif
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/boost/boost/config/compiler/hp_acc.hpp	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,36 @@
+//  (C) Copyright Boost.org 2001. Permission to copy, use, modify, sell and
+//  distribute this software is granted provided this copyright notice appears
+//  in all copies. This software is provided "as is" without express or implied
+//  warranty, and with no claim as to its suitability for any purpose.
+
+//  See http://www.boost.org for most recent version.
+
+//  HP aCC C++ compiler setup:
+
+// THIS FILE IS INCOMPLETE: WE NEED THE CORRECT VERSION CHECKS ADDING!!!
+#if (__HP_aCC <= 0) || !defined(BOOST_STRICT_CONFIG)
+#    define BOOST_NO_DEPENDENT_TYPES_IN_TEMPLATE_VALUE_PARAMETERS
+#    define BOOST_NO_OPERATORS_IN_NAMESPACE
+#  if !defined(_NAMESPACE_STD)
+#     define BOOST_NO_STD_LOCALE
+#     define BOOST_NO_STRINGSTREAM
+#  endif
+#endif
+
+
+#define BOOST_COMPILER "HP aCC version " BOOST_STRINGIZE(__HP_aCC)
+
+//
+// versions check:
+// we don't support HP aCC prior to version 0:
+#if __HP_aCC < 0
+#  error "Compiler not supported or configured - please reconfigure"
+#endif
+//
+// last known and checked version is 0:
+#if (__HP_aCC > 0)
+#  if defined(BOOST_ASSERT_CONFIG)
+#     error "Unknown compiler version - please run the configure tests and report the results"
+#  endif
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/boost/boost/config/compiler/intel.hpp	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,61 @@
+//  (C) Copyright Boost.org 2001. Permission to copy, use, modify, sell and
+//  distribute this software is granted provided this copyright notice appears
+//  in all copies. This software is provided "as is" without express or implied
+//  warranty, and with no claim as to its suitability for any purpose.
+
+//  See http://www.boost.org for most recent version.
+
+//  Intel compiler setup:
+
+#include "boost/config/compiler/common_edg.hpp"
+
+#ifdef __ICL
+#  define BOOST_COMPILER "Intel C++ version " BOOST_STRINGIZE(__ICL)
+#  define BOOST_INTEL_CXX_VERSION __ICL
+#else
+#  define BOOST_COMPILER "Intel C++ version " BOOST_STRINGIZE(__ICC)
+#  define BOOST_INTEL_CXX_VERSION __ICC
+#endif
+
+#if (BOOST_INTEL_CXX_VERSION <= 600) || !defined(BOOST_STRICT_CONFIG)
+
+#  if defined(_MSC_VER)
+      // Intel C++ 5.0.1 uses EDG 2.45, but fails to activate Koenig lookup
+      // in the frontend even in "strict" mode.  (reported by Kirk Klobe)
+      // Intel C++ 6.0 (currently in Beta test) doesn't have any front-end
+      // changes at all.  (reported by Kirk Klobe)
+#     ifndef BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP
+#        define BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP
+#     endif
+#     define BOOST_NO_EXPLICIT_FUNCTION_TEMPLATE_ARGUMENTS
+#     define BOOST_NO_SWPRINTF
+#     define BOOST_NO_INCLASS_MEMBER_INITIALIZATION
+#  endif
+
+#endif
+
+#ifdef _MSC_VER
+#  ifndef _NATIVE_WCHAR_T_DEFINED
+#     define BOOST_NO_INTRINSIC_WCHAR_T
+#  endif
+#  define BOOST_NO_SWPRINTF
+#endif
+
+
+//
+// versions check:
+// we don't support Intel prior to version 5.0:
+#if BOOST_INTEL_CXX_VERSION < 500
+#  error "Compiler not supported or configured - please reconfigure"
+#endif
+//
+// last known and checked version is 500:
+#if (BOOST_INTEL_CXX_VERSION > 500)
+#  if defined(BOOST_ASSERT_CONFIG)
+#     error "Unknown compiler version - please run the configure tests and report the results"
+#  elif defined(_MSC_VER)
+#     warning "Unknown compiler version - please run the configure tests and report the results"
+#  endif
+#endif
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/boost/boost/config/compiler/kai.hpp	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,27 @@
+//  (C) Copyright Boost.org 2001. Permission to copy, use, modify, sell and
+//  distribute this software is granted provided this copyright notice appears
+//  in all copies. This software is provided "as is" without express or implied
+//  warranty, and with no claim as to its suitability for any purpose.
+
+//  See http://www.boost.org for most recent version.
+
+//  Kai C++ compiler setup:
+
+#include "boost/config/compiler/common_edg.hpp"
+
+#   if (__KCC_VERSION <= 4001) || !defined(BOOST_STRICT_CONFIG)
+      // at least on Sun, the contents of <cwchar> is not in namespace std
+#     define BOOST_NO_STDC_NAMESPACE
+#   endif
+
+#define BOOST_COMPILER "Kai C++ version " BOOST_STRINGIZE(__KCC_VERSION)
+
+//
+// last known and checked version is 4001:
+#if (__KCC_VERSION > 4001)
+#  if defined(BOOST_ASSERT_CONFIG)
+#     error "Unknown compiler version - please run the configure tests and report the results"
+#  endif
+#endif
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/boost/boost/config/compiler/metrowerks.hpp	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,50 @@
+//  (C) Copyright Boost.org 2001. Permission to copy, use, modify, sell and
+//  distribute this software is granted provided this copyright notice appears
+//  in all copies. This software is provided "as is" without express or implied
+//  warranty, and with no claim as to its suitability for any purpose.
+
+//  See http://www.boost.org for most recent version.
+
+//  Metrowerks C++ compiler setup:
+
+#   if __MWERKS__ <= 0x2301  // 5.3
+#     define BOOST_NO_FUNCTION_TEMPLATE_ORDERING
+#     define BOOST_NO_POINTER_TO_MEMBER_CONST
+#     define BOOST_NO_DEPENDENT_TYPES_IN_TEMPLATE_VALUE_PARAMETERS
+#     define BOOST_NO_MEMBER_TEMPLATE_KEYWORD
+#   endif
+
+#   if __MWERKS__ <= 0x2401  // 6.2
+//#     define BOOST_NO_FUNCTION_TEMPLATE_ORDERING
+#   endif
+
+#   if(__MWERKS__ <= 0x2405) || !defined(BOOST_STRICT_CONFIG)  // 7.0
+#     define BOOST_NO_MEMBER_TEMPLATE_FRIENDS
+#   endif
+
+#if !__option(wchar_type)
+#   define BOOST_NO_INTRINSIC_WCHAR_T
+#endif
+
+
+#define BOOST_COMPILER "Metrowerks CodeWarrior C++ version " BOOST_STRINGIZE(__MWERKS__)
+
+//
+// versions check:
+// we don't support Metrowerks prior to version 5.3:
+#if __MWERKS__ < 0x2301
+#  error "Compiler not supported or configured - please reconfigure"
+#endif
+//
+// last known and checked version is 0x2405:
+#if (__MWERKS__ > 0x2405)
+#  if defined(BOOST_ASSERT_CONFIG)
+#     error "Unknown compiler version - please run the configure tests and report the results"
+#  endif
+#endif
+
+
+
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/boost/boost/config/compiler/mpw.hpp	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,49 @@
+//  (C) Copyright Boost.org 2001. Permission to copy, use, modify, sell and
+//  distribute this software is granted provided this copyright notice appears
+//  in all copies. This software is provided "as is" without express or implied
+//  warranty, and with no claim as to its suitability for any purpose.
+
+//  See http://www.boost.org for most recent version.
+
+//  MPW C++ compilers setup:
+
+#   if    defined(__SC__)
+#     define BOOST_COMPILER "MPW SCpp version " BOOST_STRINGIZE(__SC__)
+#   elif defined(__MRC__)
+#     define BOOST_COMPILER "MPW MrCpp version " BOOST_STRINGIZE(__MRC__)
+#   else
+#     error "Using MPW compiler configuration by mistake.  Please update."
+#   endif
+
+//
+// MPW 8.90:
+//
+#if (MPW_CPLUS <= 0x890) || !defined(BOOST_STRICT_CONFIG)
+#  define BOOST_NO_CV_SPECIALIZATIONS
+#  define BOOST_NO_DEPENDENT_NESTED_DERIVATIONS
+#  define BOOST_NO_DEPENDENT_TYPES_IN_TEMPLATE_VALUE_PARAMETERS
+#  define BOOST_NO_INCLASS_MEMBER_INITIALIZATION
+#  define BOOST_NO_INTRINSIC_WCHAR_T
+#  define BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
+#  define BOOST_NO_USING_TEMPLATE
+
+#  define BOOST_NO_CWCHAR
+#  define BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
+
+#  define BOOST_NO_STD_ALLOCATOR /* actually a bug with const reference overloading */
+#endif
+
+//
+// versions check:
+// we don't support MPW prior to version 8.9:
+#if MPW_CPLUS < 0x890
+#  error "Compiler not supported or configured - please reconfigure"
+#endif
+//
+// last known and checked version is 0x890:
+#if (MPW_CPLUS > 0x890)
+#  if defined(BOOST_ASSERT_CONFIG)
+#     error "Unknown compiler version - please run the configure tests and report the results"
+#  endif
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/boost/boost/config/compiler/sgi_mipspro.hpp	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,16 @@
+//  (C) Copyright Boost.org 2001. Permission to copy, use, modify, sell and
+//  distribute this software is granted provided this copyright notice appears
+//  in all copies. This software is provided "as is" without express or implied
+//  warranty, and with no claim as to its suitability for any purpose.
+
+//  See http://www.boost.org for most recent version.
+
+//  SGI C++ compiler setup:
+
+#define BOOST_COMPILER "SGI Irix compiler version " BOOST_STRINGIZE(_COMPILER_VERSION)
+
+#include "boost/config/compiler/common_edg.hpp"
+
+//
+// version check:
+// probably nothing to do here?
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/boost/boost/config/compiler/sunpro_cc.hpp	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,50 @@
+//  (C) Copyright Boost.org 2001. Permission to copy, use, modify, sell and
+//  distribute this software is granted provided this copyright notice appears
+//  in all copies. This software is provided "as is" without express or implied
+//  warranty, and with no claim as to its suitability for any purpose.
+
+//  See http://www.boost.org for most recent version.
+
+//  Sun C++ compiler setup:
+
+#    if __SUNPRO_CC >= 0x520
+       //
+       // Sunpro 5.1 and later:
+       //
+       // although sunpro 5.1 supports the syntax for
+       // inline initialization it often gets the value
+       // wrong, especially where the value is computed
+       // from other constants (J Maddock 6th May 2001)
+#      define BOOST_NO_INCLASS_MEMBER_INITIALIZATION
+       // although sunpro 5.1 supports the syntax for
+       // partial specialization, it often seems to
+       // bind to the wrong specialization.  Better
+       // to disable it until suppport becomes more stable
+       // (J Maddock 6th May 2001).
+#      define BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
+
+       // integral constant expressions with 64 bit numbers fail
+#      define BOOST_NO_INTEGRAL_INT64_T
+#    endif
+#    if __SUNPRO_CC <= 0x500
+#      define BOOST_NO_MEMBER_TEMPLATES
+#      define BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
+#    endif
+
+#define BOOST_COMPILER "Sun compiler version " BOOST_STRINGIZE(__SUNPRO_CC)
+
+//
+// versions check:
+// we don't support sunpro prior to version 4:
+#if __SUNPRO_CC < 0x400
+#error "Compiler not supported or configured - please reconfigure"
+#endif
+//
+// last known and checked version is 0x520:
+#if (__SUNPRO_CC > 0x520)
+#  if defined(BOOST_ASSERT_CONFIG)
+#     error "Unknown compiler version - please run the configure tests and report the results"
+#  endif
+#endif
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/boost/boost/config/compiler/vacpp.hpp	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,37 @@
+//  (C) Copyright Boost.org 2001. Permission to copy, use, modify, sell and
+//  distribute this software is granted provided this copyright notice appears
+//  in all copies. This software is provided "as is" without express or implied
+//  warranty, and with no claim as to its suitability for any purpose.
+
+//  See http://www.boost.org for most recent version.
+
+//  Visual Age (IBM) C++ compiler setup:
+
+#define BOOST_NO_MEMBER_TEMPLATE_FRIENDS
+#define BOOST_NO_INCLASS_MEMBER_INITIALIZATION
+
+//
+// On AIX thread support seems to be indicated by _THREAD_SAFE:
+//
+#ifdef _THREAD_SAFE
+#  define BOOST_HAS_THREADS
+#endif
+
+#define BOOST_COMPILER "IBM Visual Age" BOOST_STRINGIZE(__IBMCPP__)
+
+//
+// versions check:
+// we don't support Visual age prior to version 5:
+#if __IBMCPP__ < 500
+#error "Compiler not supported or configured - please reconfigure"
+#endif
+//
+// last known and checked version is 500:
+#if (__IBMCPP__ > 500)
+#  if defined(BOOST_ASSERT_CONFIG)
+#     error "Unknown compiler version - please run the configure tests and report the results"
+#  endif
+#endif
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/boost/boost/config/compiler/visualc.hpp	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,76 @@
+//  (C) Copyright Boost.org 2001. Permission to copy, use, modify, sell and
+//  distribute this software is granted provided this copyright notice appears
+//  in all copies. This software is provided "as is" without express or implied
+//  warranty, and with no claim as to its suitability for any purpose.
+
+//  See http://www.boost.org for most recent version.
+
+//  Microsoft Visual C++ compiler setup:
+
+#define BOOST_MSVC _MSC_VER
+
+// turn off the warnings before we #include anything
+#pragma warning( disable : 4786 ) // ident trunc to '255' chars in debug info
+#pragma warning( disable : 4503 ) // warning: decorated name length exceeded
+
+#if _MSC_VER <= 1200  // 1200 == VC++ 6.0
+#  define BOOST_NO_EXPLICIT_FUNCTION_TEMPLATE_ARGUMENTS
+#  define BOOST_NO_DEPENDENT_TYPES_IN_TEMPLATE_VALUE_PARAMETERS
+#  define BOOST_NO_VOID_RETURNS
+#endif
+
+#if (_MSC_VER <= 1300) || !defined(BOOST_STRICT_CONFIG)  // VC7 Beta 2 or later
+#  define BOOST_NO_INCLASS_MEMBER_INITIALIZATION
+#  define BOOST_NO_PRIVATE_IN_AGGREGATE
+#  define BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP
+#  define BOOST_NO_INTEGRAL_INT64_T
+
+//    VC++ 6/7 has member templates but they have numerous problems including
+//    cases of silent failure, so for safety we define:
+#  define BOOST_NO_MEMBER_TEMPLATES
+//    For VC++ experts wishing to attempt workarounds, we define:
+#  define BOOST_MSVC6_MEMBER_TEMPLATES
+
+#  define BOOST_NO_MEMBER_TEMPLATE_FRIENDS
+#  define BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
+#  define BOOST_NO_CV_VOID_SPECIALIZATIONS
+#  define BOOST_NO_FUNCTION_TEMPLATE_ORDERING
+#  define BOOST_NO_USING_TEMPLATE
+#  define BOOST_NO_SWPRINTF
+//#  define BOOST_NO_POINTER_TO_MEMBER_CONST
+   //
+   // disable min/max macros if defined:
+   //
+#  ifdef min
+#     undef min
+#  endif
+#  ifdef max
+#     undef max
+#  endif
+   // disable min/max macro defines on vc6:
+   //
+#  define NOMINMAX
+#endif
+
+#ifndef _NATIVE_WCHAR_T_DEFINED
+#  define BOOST_NO_INTRINSIC_WCHAR_T
+#endif
+
+#define BOOST_COMPILER "Microsoft Visual C++ version " BOOST_STRINGIZE(_MSC_VER)
+
+//
+// versions check:
+// we don't support Visual C++ prior to version 6:
+#if _MSC_VER < 1200
+#error "Compiler not supported or configured - please reconfigure"
+#endif
+//
+// last known and checked version is 1300:
+#if (_MSC_VER > 1300)
+#  if defined(BOOST_ASSERT_CONFIG)
+#     error "Unknown compiler version - please run the configure tests and report the results"
+#  else
+#     warning "Unknown compiler version - please run the configure tests and report the results"
+#  endif
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/boost/boost/config/platform/aix.hpp	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,20 @@
+//  (C) Copyright Boost.org 2001. Permission to copy, use, modify, sell and
+//  distribute this software is granted provided this copyright notice appears
+//  in all copies. This software is provided "as is" without express or implied
+//  warranty, and with no claim as to its suitability for any purpose.
+
+//  See http://www.boost.org for most recent version.
+
+//  IBM/Aix specific config options:
+
+#define BOOST_PLATFORM "IBM Aix"
+
+#define BOOST_HAS_UNISTD_H
+#define BOOST_HAS_PTHREADS
+#define BOOST_HAS_NL_TYPES_H
+
+// Threading API's:
+#define BOOST_HAS_PTHREAD_DELAY_NP
+#define BOOST_HAS_PTHREAD_YIELD
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/boost/boost/config/platform/beos.hpp	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,23 @@
+//  (C) Copyright Boost.org 2001. Permission to copy, use, modify, sell and
+//  distribute this software is granted provided this copyright notice appears
+//  in all copies. This software is provided "as is" without express or implied
+//  warranty, and with no claim as to its suitability for any purpose.
+
+//  See http://www.boost.org for most recent version.
+
+//  BeOS specific config options:
+
+#define BOOST_PLATFORM "BeOS"
+
+#define BOOST_NO_CWCHAR
+#define BOOST_NO_CWCTYPE
+#define BOOST_HAS_UNISTD_H
+
+#define BOOST_HAS_BETHREADS
+
+#ifndef BOOST_DISABLE_THREADS
+#  define BOOST_HAS_THREADS
+#endif
+
+ 
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/boost/boost/config/platform/bsd.hpp	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,39 @@
+//  (C) Copyright Boost.org 2001. Permission to copy, use, modify, sell and
+//  distribute this software is granted provided this copyright notice appears
+//  in all copies. This software is provided "as is" without express or implied
+//  warranty, and with no claim as to its suitability for any purpose.
+
+//  See http://www.boost.org for most recent version.
+
+//  generic BSD config options:
+
+#if !defined(__FreeBSD__) && !defined(__NetBSD__) && !defined(__OpenBSD__)
+#error "This platform is not BSD"
+#endif
+
+#ifdef __FreeBSD__
+#define BOOST_PLATFORM "FreeBSD " BOOST_STRINGIZE(__FreeBSD__)
+#elif defined(__NetBSD__)
+#define BOOST_PLATFORM "NetBSD " BOOST_STRINGIZE(__NetBSD__)
+#elif defined(__OpenBSD__)
+#define BOOST_PLATFORM "OpenBSD " BOOST_STRINGIZE(__OpenBSD__)
+#endif
+
+//
+// is this the correct version check?
+// FreeBSD has <nl_type.h> but does not
+// advertise the fact in <unistd.h>:
+//
+#if defined(__FreeBSD__) && (__FreeBSD__ >= 4)
+#  define BOOST_HAS_NL_TYPES_H
+#endif
+
+//
+// No wide character support in the BSD header files:
+//
+#define BOOST_NO_CWCHAR
+
+//
+// The BSD <ctype.h> has macros only, no functions:
+//
+#define BOOST_NO_CTYPE_FUNCTIONS
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/boost/boost/config/platform/cygwin.hpp	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,30 @@
+//  (C) Copyright Boost.org 2001. Permission to copy, use, modify, sell and
+//  distribute this software is granted provided this copyright notice appears
+//  in all copies. This software is provided "as is" without express or implied
+//  warranty, and with no claim as to its suitability for any purpose.
+
+//  See http://www.boost.org for most recent version.
+
+//  cygwin specific config options:
+
+#define BOOST_PLATFORM "Cygwin"
+#define BOOST_NO_CWCTYPE
+#define BOOST_NO_CWCHAR
+#define BOOST_NO_SWPRINTF
+
+//
+// Threading API:
+// See if we have POSIX threads, if we do use them, otherwise
+// revert to native Win threads.
+#include <unistd.h>
+#if defined(_POSIX_THREADS) && (_POSIX_THREADS+0 >= 0) && !defined(BOOST_HAS_WINTHREADS)
+#  define BOOST_HAS_PTHREADS
+#  define BOOST_HAS_SCHED_YIELD
+#  define BOOST_HAS_GETTIMEOFDAY
+#else
+#  define BOOST_HAS_WINTHREADS
+#  define BOOST_HAS_FTIME
+#endif
+
+ 
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/boost/boost/config/platform/hpux.hpp	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,19 @@
+//  (C) Copyright Boost.org 2001. Permission to copy, use, modify, sell and
+//  distribute this software is granted provided this copyright notice appears
+//  in all copies. This software is provided "as is" without express or implied
+//  warranty, and with no claim as to its suitability for any purpose.
+
+//  See http://www.boost.org for most recent version.
+
+//  hpux specific config options:
+
+#define BOOST_PLATFORM "HP-UX"
+
+// In principle, HP-UX has a nice <stdint.h> under the name <inttypes.h>
+// However, it has the following problem:
+// Use of UINT32_C(0) results in "0u l" for the preprocessed source
+// (verifyable with gcc 2.95.3, assumed for HP aCC)
+// #define BOOST_HAS_STDINT_H
+
+#define BOOST_NO_SWPRINTF 
+#define BOOST_NO_CWCTYPE
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/boost/boost/config/platform/irix.hpp	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,13 @@
+//  (C) Copyright Boost.org 2001. Permission to copy, use, modify, sell and
+//  distribute this software is granted provided this copyright notice appears
+//  in all copies. This software is provided "as is" without express or implied
+//  warranty, and with no claim as to its suitability for any purpose.
+
+//  See http://www.boost.org for most recent version.
+
+//  SGI Irix specific config options:
+
+#define BOOST_PLATFORM "SGI Irix"
+
+#define BOOST_NO_SWPRINTF 
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/boost/boost/config/platform/linux.hpp	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,64 @@
+//  (C) Copyright Boost.org 2001. Permission to copy, use, modify, sell and
+//  distribute this software is granted provided this copyright notice appears
+//  in all copies. This software is provided "as is" without express or implied
+//  warranty, and with no claim as to its suitability for any purpose.
+
+//  See http://www.boost.org for most recent version.
+
+//  linux specific config options:
+
+#define BOOST_PLATFORM "linux"
+
+// make sure we have __GLIBC_PREREQ if available at all
+#include <cstdlib>
+
+//
+// <stdint.h> added to glibc 2.1.1
+// We can only test for 2.1 though:
+//
+#if defined(__GLIBC__) && ((__GLIBC__ > 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ >= 1)))
+   // <stdint.h> defines int64_t unconditionally, but <sys/types.h> defines
+   // int64_t only if __GNUC__.  Thus, assume a fully usable <stdint.h>
+   // only when using GCC.
+#  if defined __GNUC__
+#    define BOOST_HAS_STDINT_H
+#  endif
+#endif
+
+#if defined(__GLIBC__) && defined(__GLIBC_PREREQ)
+// __GLIBC_PREREQ is available since 2.1.2
+
+   // swprintf is available since glibc 2.2.0
+#  if !__GLIBC_PREREQ(2,2) || (!defined(__USE_ISOC99) && !defined(__USE_UNIX98))
+#    define BOOST_NO_SWPRINTF
+#  endif
+#else
+#  define BOOST_NO_SWPRINTF
+#endif
+
+#ifndef __GNUC__
+//
+// if the compiler is not gcc we still need to be able to parse
+// the GNU system headers, some of which (mainly <stdint.h>)
+// use GNU specific extensions:
+//
+#  ifndef __extension__
+#     define __extension__
+#  endif
+#  ifndef __const__
+#     define __const__ const
+#  endif
+#  ifndef __volatile__
+#     define __volatile__ volatile
+#  endif
+#  ifndef __signed__
+#     define __signed__ signed
+#  endif
+#  ifndef __typeof__
+#     define __typeof__ typeof
+#  endif
+#  ifndef __inline__
+#     define __inline__ inline
+#  endif
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/boost/boost/config/platform/macos.hpp	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,32 @@
+//  (C) Copyright Boost.org 2001. Permission to copy, use, modify, sell and
+//  distribute this software is granted provided this copyright notice appears
+//  in all copies. This software is provided "as is" without express or implied
+//  warranty, and with no claim as to its suitability for any purpose.
+
+//  See http://www.boost.org for most recent version.
+
+//  Mac OS specific config options:
+
+#define BOOST_PLATFORM "Mac OS"
+
+// If __MACH__, we're using the BSD standard C library, not the MSL:
+#if defined(__MACH__)
+
+#  define BOOST_NO_CTYPE_FUNCTIONS
+#  define BOOST_NO_CWCHAR
+#  ifndef BOOST_HAS_UNISTD_H
+#    define BOOST_HAS_UNISTD_H
+#  endif
+#  ifndef BOOST_HAS_STDINT_H
+#     define BOOST_HAS_STDINT_H
+#  endif
+
+#  ifndef __APPLE_CC__
+
+// GCC strange "ignore std" mode works better if you pretend everything
+// is in the std namespace, for the most part.
+
+#    define BOOST_NO_STDC_NAMESPACE
+#  endif
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/boost/boost/config/platform/solaris.hpp	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,13 @@
+//  (C) Copyright Boost.org 2001. Permission to copy, use, modify, sell and
+//  distribute this software is granted provided this copyright notice appears
+//  in all copies. This software is provided "as is" without express or implied
+//  warranty, and with no claim as to its suitability for any purpose.
+
+//  See http://www.boost.org for most recent version.
+
+//  sun specific config options:
+
+#define BOOST_PLATFORM "sun"
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/boost/boost/config/platform/win32.hpp	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,36 @@
+//  (C) Copyright Boost.org 2001. Permission to copy, use, modify, sell and
+//  distribute this software is granted provided this copyright notice appears
+//  in all copies. This software is provided "as is" without express or implied
+//  warranty, and with no claim as to its suitability for any purpose.
+
+//  See http://www.boost.org for most recent version.
+
+//  Win32 specific config options:
+
+#define BOOST_PLATFORM "Win32"
+
+#if defined BOOST_DECL_EXPORTS
+#  if defined BOOST_DECL_IMPORTS
+#     error Not valid to define both BOOST_DECL_EXPORTS and BOOST_DECL_IMPORTS
+#  endif
+#  define BOOST_DECL __declspec(dllexport)
+#elif defined BOOST_DECL_IMPORTS
+#  define BOOST_DECL __declspec(dllimport)
+#else
+#  define BOOST_DECL
+#endif
+
+#if defined(__GNUC__) && !defined(BOOST_NO_SWPRINTF)
+#  define BOOST_NO_SWPRINTF
+#endif
+
+//
+// Win32 will normally be using native Win32 threads,
+// but there is a pthread library avaliable as an option:
+//
+#ifndef BOOST_HAS_PTHREADS
+#  define BOOST_HAS_WINTHREADS
+#endif
+
+// WEK: Added
+#define BOOST_HAS_FTIME
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/boost/boost/config/posix_features.hpp	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,65 @@
+//  (C) Copyright Boost.org 2001. Permission to copy, use, modify, sell and
+//  distribute this software is granted provided this copyright notice appears
+//  in all copies. This software is provided "as is" without express or implied
+//  warranty, and with no claim as to its suitability for any purpose.
+
+//  See http://www.boost.org for most recent version.
+
+// All POSIX feature tests go in this file:
+
+#  ifdef BOOST_HAS_UNISTD_H
+#     include <unistd.h>
+
+      // XOpen has <nl_types.h>, but is this the correct version check?
+#     if defined(_XOPEN_VERSION) && (_XOPEN_VERSION >= 3)
+#        define BOOST_HAS_NL_TYPES_H
+#     endif
+
+      // POSIX version 6 requires <stdint.h>
+#     if defined(_POSIX_VERSION) && (_POSIX_VERSION >= 200100)
+#        define BOOST_HAS_STDINT_H
+#     endif
+
+      // POSIX defines _POSIX_THREADS > 0 for pthread support,
+      // however some platforms define _POSIX_THREADS without
+      // a value, hence the (_POSIX_THREADS+0 >= 0) check.
+      // Strictly speaking this may catch platforms with a
+      // non-functioning stub <pthreads.h>, but such occurrences should
+      // occur very rarely if at all.
+#     if defined(_POSIX_THREADS) && (_POSIX_THREADS+0 >= 0) && !defined(BOOST_HAS_WINTHREADS)
+#        define BOOST_HAS_PTHREADS
+#     endif
+
+      // BOOST_HAS_NANOSLEEP:
+      // This is predicated on _POSIX_TIMERS:
+#     if defined(_POSIX_TIMERS) && (_POSIX_TIMERS+0 >= 0)
+#        define BOOST_HAS_NANOSLEEP
+#     endif
+
+      // BOOST_HAS_SCHED_YIELD:
+      // This is predicated on _POSIX_PRIORITY_SCHEDULING or
+      // on _POSIX_THREAD_PRIORITY_SCHEDULING.
+#     if defined(_POSIX_PRIORITY_SCHEDULING) && (_POSIX_PRIORITY_SCHEDULING+0 > 0)
+#        define BOOST_HAS_SCHED_YIELD
+#     endif
+#     if defined(_POSIX_THREAD_PRIORITY_SCHEDULING) && (_POSIX_THREAD_PRIORITY_SCHEDULING+0 > 0)
+#        define BOOST_HAS_SCHED_YIELD
+#     endif
+
+      // BOOST_HAS_GETTIMEOFDAY:
+      // BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE:
+      // These are predicated on _XOPEN_VERSION, and appears to be first released
+      // in issue 4, version 2 (_XOPEN_VERSION > 500).
+#     if defined(_XOPEN_VERSION) && (_XOPEN_VERSION+0 > 500)
+#        define BOOST_HAS_GETTIMEOFDAY
+#        define BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE
+#     endif
+
+      // BOOST_HAS_CLOCK_GETTIME:
+      // This is predicated on _POSIX_TIMERS.
+#     if defined(_POSIX_TIMERS) && (_POSIX_TIMERS+0 > 0)
+#        define BOOST_HAS_CLOCK_GETTIME
+#     endif
+
+
+#  endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/boost/boost/config/select_compiler_config.hpp	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,77 @@
+//  Boost compiler configuration selection header file
+
+//  (C) Copyright Boost.org 2001. Permission to copy, use, modify, sell and
+//  distribute this software is granted provided this copyright notice appears
+//  in all copies. This software is provided "as is" without express or implied
+//  warranty, and with no claim as to its suitability for any purpose.
+
+//  See http://www.boost.org for most recent version.
+
+// locate which compiler we are using and define
+// BOOST_COMPILER_CONFIG as needed: 
+
+#if defined __GNUC__
+//  GNU C++:
+#   define BOOST_COMPILER_CONFIG "boost/config/compiler/gcc.hpp"
+
+#elif defined __KCC
+//  Kai C++
+#   define BOOST_COMPILER_CONFIG "boost/config/compiler/kai.hpp"
+
+#elif defined __sgi
+//  SGI MIPSpro C++
+#   define BOOST_COMPILER_CONFIG "boost/config/compiler/sgi_mipspro.hpp"
+
+#elif defined __DECCXX
+//  Compaq Tru64 Unix cxx
+#   define BOOST_COMPILER_CONFIG "boost/config/compiler/compaq_cxx.hpp"
+
+#elif defined __ghs
+//  Greenhills C++
+#   define BOOST_COMPILER_CONFIG "boost/config/compiler/greenhills.hpp"
+
+#elif defined __BORLANDC__
+//  Borland
+#   define BOOST_COMPILER_CONFIG "boost/config/compiler/borland.hpp"
+
+#elif defined(__ICL) || defined(__ICC)
+//  Intel
+#   define BOOST_COMPILER_CONFIG "boost/config/compiler/intel.hpp"
+
+#elif defined  __MWERKS__
+//  Metrowerks CodeWarrior
+#   define BOOST_COMPILER_CONFIG "boost/config/compiler/metrowerks.hpp"
+
+#elif defined  __SUNPRO_CC
+//  Sun Workshop Compiler C++
+#   define BOOST_COMPILER_CONFIG "boost/config/compiler/sunpro_cc.hpp"
+
+#elif defined __HP_aCC
+//  HP aCC
+#   define BOOST_COMPILER_CONFIG "boost/config/compiler/hp_acc.hpp"
+
+#elif defined(__MRC__) || defined(__SC__)
+//  MPW MrCpp or SCpp
+#   define BOOST_COMPILER_CONFIG "boost/config/compiler/mpw.hpp"
+
+#elif defined(__IBMCPP__)
+//  IBM Visual Age
+#   define BOOST_COMPILER_CONFIG "boost/config/compiler/vacpp.hpp"
+
+# elif defined __COMO__
+//  Comeau C++
+#   define BOOST_COMPILER_CONFIG "boost/config/compiler/comeau.hpp"
+
+#elif defined _MSC_VER
+//  Microsoft Visual C++
+//
+//  Must remain the last #elif since some other vendors (Metrowerks, for
+//  example) also #define _MSC_VER
+#   define BOOST_COMPILER_CONFIG "boost/config/compiler/visualc.hpp"
+
+#elif defined (BOOST_ASSERT_CONFIG)
+// this must come last - generate an error if we don't
+// recognise the compiler:
+#  error "Unknown compiler - please configure and report the results to boost.org"
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/boost/boost/config/select_platform_config.hpp	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,62 @@
+//  Boost compiler configuration selection header file
+
+//  (C) Copyright Boost.org 2001. Permission to copy, use, modify, sell and
+//  distribute this software is granted provided this copyright notice appears
+//  in all copies. This software is provided "as is" without express or implied
+//  warranty, and with no claim as to its suitability for any purpose.
+
+//  See http://www.boost.org for most recent version.
+
+// locate which platform we are on and define BOOST_PLATFORM_CONFIG as needed.
+// Note that we define the headers to include using "header_name" not
+// <header_name> in order to prevent macro expansion within the header
+// name (for example "linux" is a macro on linux systems).
+
+#if defined(linux) || defined(__linux) || defined(__linux__)
+// linux:
+#  define BOOST_PLATFORM_CONFIG "boost/config/platform/linux.hpp"
+
+#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
+// BSD:
+#  define BOOST_PLATFORM_CONFIG "boost/config/platform/bsd.hpp"
+
+#elif defined(sun) || defined(__sun)
+// solaris:
+#  define BOOST_PLATFORM_CONFIG "boost/config/platform/solaris.hpp"
+
+#elif defined(__sgi)
+// SGI Irix:
+#  define BOOST_PLATFORM_CONFIG "boost/config/platform/irix.hpp"
+
+#elif defined(__hpux)
+// hp unix:
+#  define BOOST_PLATFORM_CONFIG "boost/config/platform/hpux.hpp"
+
+#elif defined(__CYGWIN__)
+// cygwin is not win32:
+#  define BOOST_PLATFORM_CONFIG "boost/config/platform/cygwin.hpp"
+
+#elif defined(_WIN32) || defined(__WIN32__) || defined(WIN32)
+// win32:
+#  define BOOST_PLATFORM_CONFIG "boost/config/platform/win32.hpp"
+
+#elif defined(__BEOS__)
+// BeOS
+#  define BOOST_PLATFORM_CONFIG "boost/config/platform/beos.hpp"
+
+#elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__)
+// MacOS
+#  define BOOST_PLATFORM_CONFIG "boost/config/platform/macos.hpp"
+
+#elif defined(__IBMCPP__)
+// IBM
+#  define BOOST_PLATFORM_CONFIG "boost/config/platform/aix.hpp"
+
+#elif defined (BOOST_ASSERT_CONFIG)
+// this must come last - generate an error if we don't
+// recognise the platform:
+#  error "Unknown platform - please configure and report the results to boost.org"
+
+#endif
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/boost/boost/config/select_stdlib_config.hpp	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,61 @@
+//  Boost compiler configuration selection header file
+
+//  (C) Copyright Boost.org 2001. Permission to copy, use, modify, sell and
+//  distribute this software is granted provided this copyright notice appears
+//  in all copies. This software is provided "as is" without express or implied
+//  warranty, and with no claim as to its suitability for any purpose.
+
+//  See http://www.boost.org for most recent version.
+
+// locate which std lib we are using and define BOOST_STDLIB_CONFIG as needed:
+
+// we need to include a std lib header here in order to detect which
+// library is in use, use <utility> as it's about the smallest
+// of the std lib headers - do not rely on this header being included -
+// users can short-circuit this header if they know whose std lib
+// they are using.
+
+#include <utility>
+
+#if defined(__SGI_STL_PORT) || defined(_STLPORT_VERSION)
+// STLPort library; this _must_ come first, otherwise since
+// STLport typically sits on top of some other library, we
+// can end up detecting that first rather than STLport:
+#  define BOOST_STDLIB_CONFIG "boost/config/stdlib/stlport.hpp"
+
+#elif defined(__STD_RWCOMPILER_H__) || defined(_RWSTD_VER)
+// Rogue Wave library:
+#  define BOOST_STDLIB_CONFIG "boost/config/stdlib/roguewave.hpp"
+
+#elif (defined(_YVALS) && !defined(__IBMCPP__)) || defined(_CPPLIB_VER)
+// Dinkumware Library:
+#  define BOOST_STDLIB_CONFIG "boost/config/stdlib/dinkumware.hpp"
+
+#elif defined(__GLIBCPP__)
+// GNU libstdc++ 3
+#  define BOOST_STDLIB_CONFIG "boost/config/stdlib/libstdcpp3.hpp"
+
+#elif defined(__STL_CONFIG_H)
+// generic SGI STL
+#  define BOOST_STDLIB_CONFIG "boost/config/stdlib/sgi.hpp"
+
+#elif defined(__MSL_CPP__)
+// MSL standard lib:
+#  define BOOST_STDLIB_CONFIG "boost/config/stdlib/msl.hpp"
+
+#elif defined(__IBMCPP__)
+// take the default VACPP std lib
+#  define BOOST_STDLIB_CONFIG "boost/config/stdlib/vacpp.hpp"
+
+#elif defined(MSIPL_COMPILE_H)
+// Modena C++ standard library
+#  define BOOST_STDLIB_CONFIG "boost/config/stdlib/modena.hpp"
+
+#elif defined (BOOST_ASSERT_CONFIG)
+// this must come last - generate an error if we don't
+// recognise the library:
+#  error "Unknown standard library - please configure and report the results to boost.org"
+
+#endif
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/boost/boost/config/stdlib/dinkumware.hpp	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,71 @@
+//  (C) Copyright Boost.org 2001. Permission to copy, use, modify, sell and
+//  distribute this software is granted provided this copyright notice appears
+//  in all copies. This software is provided "as is" without express or implied
+//  warranty, and with no claim as to its suitability for any purpose.
+
+//  See http://www.boost.org for most recent version.
+
+//  Dinkumware standard library config:
+
+#if !defined(_YVALS) && !defined(_CPPLIB_VER)
+#include <utility>
+#if !defined(_YVALS) && !defined(_CPPLIB_VER)
+#error This is not the Dinkumware lib!
+#endif
+#endif
+
+
+#if defined(_CPPLIB_VER) && (_CPPLIB_VER >= 306)
+   // full dinkumware 3.06 and above
+   // fully conforming provided the compiler supports it:
+#  if !(defined(_GLOBAL_USING) && (_GLOBAL_USING+0 > 0)) && !defined(_STD)   // can be defined in yvals.h
+#     define BOOST_NO_STDC_NAMESPACE
+#  endif
+#  if !(defined(_HAS_MEMBER_TEMPLATES_REBIND) && (_HAS_MEMBER_TEMPLATES_REBIND+0 > 0))
+#     define BOOST_NO_STD_ALLOCATOR
+#  endif
+#  if defined(_MSC_VER) && (_MSC_VER < 1300)
+      // if this lib version is set up for vc6 then there is no std::use_facet:
+#     define BOOST_NO_STD_USE_FACET
+#     define BOOST_HAS_TWO_ARG_USE_FACET
+#  endif
+// 3.06 appears to have (non-sgi versions of) <hash_set> & <hash_map>, 
+// and no <slist> at all
+#else
+#  define BOOST_MSVC_STD_ITERATOR 1
+#  define BOOST_NO_STD_ITERATOR
+#  define BOOST_NO_TEMPLATED_ITERATOR_CONSTRUCTORS
+#  define BOOST_NO_STD_ALLOCATOR
+#  define BOOST_NO_STDC_NAMESPACE
+#  define BOOST_NO_STD_USE_FACET
+#  define BOOST_NO_STD_OUTPUT_ITERATOR_ASSIGN
+#  define BOOST_HAS_MACRO_USE_FACET
+#  ifndef _CPPLIB_VER
+      // Updated Dinkum library defines this, and provides
+      // its own min and max definitions.
+#     define BOOST_NO_STD_MIN_MAX
+#     undef min
+#     undef max
+#  endif
+#  ifndef NOMINMAX
+      // avoid spurious NOMINMAX redefinition warning
+#     define NOMINMAX
+#  endif
+#endif
+
+#if defined(_MSC_VER) && (_MSC_VER <= 1200)
+   // if we're using a dinkum lib that's
+   // been configured for VC6 then there is
+   // no iterator traits (true even for icl)
+#  define BOOST_NO_STD_ITERATOR_TRAITS
+#endif
+
+#ifdef _CPPLIB_VER
+#  define BOOST_STDLIB "Dinkumware standard library version " BOOST_STRINGIZE(_CPPLIB_VER)
+#else
+#  define BOOST_STDLIB "Dinkumware standard library version 1.x"
+#endif
+
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/boost/boost/config/stdlib/libstdcpp3.hpp	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,20 @@
+//  (C) Copyright Boost.org 2001. Permission to copy, use, modify, sell and
+//  distribute this software is granted provided this copyright notice appears
+//  in all copies. This software is provided "as is" without express or implied
+//  warranty, and with no claim as to its suitability for any purpose.
+
+//  See http://www.boost.org for most recent version.
+
+//  config for libstdc++ v3
+//  not much to go in here:
+
+#define BOOST_STDLIB "GNU libstdc++ version " BOOST_STRINGIZE(__GLIBCPP__)
+
+#ifndef _GLIBCPP_USE_WCHAR_T
+#  define BOOST_NO_CWCHAR
+#  define BOOST_NO_CWCTYPE
+#  define BOOST_NO_STD_WSTRING
+#endif
+ 
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/boost/boost/config/stdlib/modena.hpp	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,29 @@
+//  (C) Copyright Boost.org 2001. Permission to copy, use, modify, sell and
+//  distribute this software is granted provided this copyright notice appears
+//  in all copies. This software is provided "as is" without express or implied
+//  warranty, and with no claim as to its suitability for any purpose.
+
+//  See http://www.boost.org for most recent version.
+
+//  Modena C++ standard library (comes with KAI C++)
+
+#if !defined(MSIPL_COMPILE_H)
+#  include <utility>
+#  if !defined(__MSIPL_COMPILE_H)
+#      error "This is not the Modena C++ library!"
+#  endif
+#endif
+
+#ifndef MSIPL_NL_TYPES
+#define BOOST_NO_STD_MESSAGES
+#endif
+
+#ifndef MSIPL_WCHART
+#define BOOST_NO_STD_WSTRING
+#endif
+
+#define BOOST_STDLIB "Modena C++ standard library"
+
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/boost/boost/config/stdlib/msl.hpp	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,44 @@
+//  (C) Copyright Boost.org 2001. Permission to copy, use, modify, sell and
+//  distribute this software is granted provided this copyright notice appears
+//  in all copies. This software is provided "as is" without express or implied
+//  warranty, and with no claim as to its suitability for any purpose.
+
+//  See http://www.boost.org for most recent version.
+
+//  Metrowerks standard library:
+
+#ifndef __MSL_CPP__
+#  include <utility>
+#  ifndef __MSL_CPP__
+#     error This is not the MSL standard library!
+#  endif
+#endif
+
+#if __MSL_CPP__ >= 0x6000  // Pro 6
+#  define BOOST_HAS_HASH
+#  define BOOST_STD_EXTENSION_NAMESPACE Metrowerks
+#endif
+#define BOOST_HAS_SLIST
+
+#if __MSL_CPP__ < 0x6209
+#  define BOOST_NO_STD_MESSAGES
+#endif
+
+// check C lib version for <stdint.h>
+#include <cstddef>
+
+#if defined(__MSL__) && (__MSL__ >= 0x5000)
+#  define BOOST_HAS_STDINT_H
+#  define BOOST_HAS_UNISTD_H
+#endif
+
+
+#define BOOST_STDLIB "Metrowerks Standard Library version " BOOST_STRINGIZE(__MSL_CPP__)
+
+
+
+
+
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/boost/boost/config/stdlib/roguewave.hpp	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,106 @@
+//  (C) Copyright Boost.org 2001. Permission to copy, use, modify, sell and
+//  distribute this software is granted provided this copyright notice appears
+//  in all copies. This software is provided "as is" without express or implied
+//  warranty, and with no claim as to its suitability for any purpose.
+
+//  See http://www.boost.org for most recent version.
+
+//  Rogue Wave std lib:
+
+#if !defined(__STD_RWCOMPILER_H__) && !defined(_RWSTD_VER)
+#  include <utility>
+#  if !defined(__STD_RWCOMPILER_H__) && !defined(_RWSTD_VER)
+#     error This is not the Rogue Wave standard library
+#  endif
+#endif
+//
+// figure out a consistent version number:
+//
+#ifndef _RWSTD_VER
+#  define BOOST_RWSTD_VER 0x010000
+#elif _RWSTD_VER < 0x010000
+#  define BOOST_RWSTD_VER (_RWSTD_VER << 8)
+#else
+#  define BOOST_RWSTD_VER _RWSTD_VER
+#endif
+
+#ifndef _RWSTD_VER
+#  define BOOST_STDLIB "Rogue Wave standard library version (Unknown version)"
+#else
+#  define BOOST_STDLIB "Rogue Wave standard library version " BOOST_STRINGIZE(_RWSTD_VER)
+#endif
+
+//
+// Prior to version 2.2.0 the primary template for std::numeric_limits
+// does not have compile time constants, even though specializations of that
+// template do:
+//
+#if BOOST_RWSTD_VER < 0x020200
+#  define BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
+#endif
+
+//
+// No std::iterator if it can't figure out default template args:
+//
+#if defined(_RWSTD_NO_SIMPLE_DEFAULT_TEMPLATES) || defined(RWSTD_NO_SIMPLE_DEFAULT_TEMPLATES) || (BOOST_RWSTD_VER < 0x020000)
+#  define BOOST_NO_STD_ITERATOR
+#endif
+
+//
+// No iterator traits without partial specialization:
+//
+#if defined(_RWSTD_NO_CLASS_PARTIAL_SPEC) || defined(RWSTD_NO_CLASS_PARTIAL_SPEC)
+#  define BOOST_NO_STD_ITERATOR_TRAITS
+#endif
+
+//
+// Prior to version 2.0, std::auto_ptr was buggy, and there were no
+// new-style iostreams, and no conformant std::allocator:
+//
+#if (BOOST_RWSTD_VER < 0x020000)
+#  define BOOST_NO_AUTO_PTR
+#  define BOOST_NO_STRINGSTREAM
+#  define BOOST_NO_STD_ALLOCATOR
+#  define BOOST_NO_STD_LOCALE
+#endif
+
+//
+// No template iterator constructors without member template support:
+//
+#if defined(RWSTD_NO_MEMBER_TEMPLATES) || defined(_RWSTD_NO_MEMBER_TEMPLATES)
+#  define BOOST_NO_TEMPLATED_ITERATOR_CONSTRUCTORS
+#endif
+
+//
+// RW defines _RWSTD_ALLOCATOR if the allocator is conformant and in use
+// (the or _HPACC_ part is a hack - the library seems to define _RWSTD_ALLOCATOR
+// on HP aCC systems even though the allocator is in fact broken):
+//
+#if !defined(_RWSTD_ALLOCATOR) || defined(_HPACC_) || defined(__HP_aCC)
+#  define BOOST_NO_STD_ALLOCATOR
+#endif
+
+//
+// If we have a std::locale, we still may not have std::use_facet:
+//
+#if defined(_RWSTD_NO_TEMPLATE_ON_RETURN_TYPE) && !defined(BOOST_NO_STD_LOCALE)
+#  define BOOST_NO_STD_USE_FACET
+#  define BOOST_HAS_TWO_ARG_USE_FACET
+#endif
+
+//
+// There's no std::distance prior to version 2, or without
+// partial specialization support:
+//
+#if (BOOST_RWSTD_VER < 0x020000) || defined(_RWSTD_NO_CLASS_PARTIAL_SPEC)
+    #define BOOST_NO_STD_DISTANCE
+#endif
+
+//
+// Some versions of the rogue wave library don't have assignable
+// OutputIterators:
+//
+#if BOOST_RWSTD_VER < 0x020100
+#  define BOOST_NO_STD_OUTPUT_ITERATOR_ASSIGN
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/boost/boost/config/stdlib/sgi.hpp	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,77 @@
+//  (C) Copyright Boost.org 2001. Permission to copy, use, modify, sell and
+//  distribute this software is granted provided this copyright notice appears
+//  in all copies. This software is provided "as is" without express or implied
+//  warranty, and with no claim as to its suitability for any purpose.
+
+//  See http://www.boost.org for most recent version.
+
+//  generic SGI STL:
+
+#if !defined(__STL_CONFIG_H)
+#  include <utility>
+#  if !defined(__STL_CONFIG_H)
+#      error "This is not the SGI STL!"
+#  endif
+#endif
+
+//
+// No std::iterator traits without partial specialisation:
+//
+#if !defined(__STL_CLASS_PARTIAL_SPECIALIZATION)
+#  define BOOST_NO_STD_ITERATOR_TRAITS
+#endif
+
+//
+// No std::stringstream with gcc < 3
+//
+#if defined(__GNUC__) && (__GNUC__ < 3) && (__GNUC_MINOR__ < 95) && !defined(__STL_USE_NEW_IOSTREAMS) || defined(__APPLE_CC__)
+   // Note that we only set this for gnu C++ prior to 2.95 since the
+   // latest patches for that release do contain a minimal <sstream>
+   // If you are running a 2.95 release prior to 2.95.3 then this will need
+   // setting, but there is no way to detect that automatically (other
+   // than by running the configure script).
+#  define BOOST_NO_STRINGSTREAM
+#endif
+
+//
+// Assume no std::locale without own iostreams (this may be an
+// incorrect assumption in some cases):
+//
+#if !defined(__SGI_STL_OWN_IOSTREAMS) && !defined(__STL_USE_NEW_IOSTREAMS)
+#  define BOOST_NO_STD_LOCALE
+#endif
+
+//
+// No template iterator constructors, or std::allocator
+// without member templates:
+//
+#if !defined(__STL_MEMBER_TEMPLATES)
+#  define BOOST_NO_TEMPLATED_ITERATOR_CONSTRUCTORS
+#  define BOOST_NO_STD_ALLOCATOR
+#endif
+
+//
+// We always have SGI style hash_set, hash_map, and slist:
+//
+#define BOOST_HAS_HASH
+#define BOOST_HAS_SLIST
+
+//
+// If this is GNU libstdc++2, then no <limits> and no std::wstring:
+//
+#if (defined(__GNUC__) && (__GNUC__ < 3))
+#  include <string>
+#  if defined(__BASTRING__)
+#     define BOOST_NO_LIMITS
+#     define BOOST_NO_STD_WSTRING
+#  endif
+#endif
+
+//
+// There is no standard iterator unless we have namespace support:
+//
+#if !defined(__STL_USE_NAMESPACES)
+#  define BOOST_NO_STD_ITERATOR
+#endif
+
+#define BOOST_STDLIB "SGI standard library"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/boost/boost/config/stdlib/stlport.hpp	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,105 @@
+//  (C) Copyright Boost.org 2001. Permission to copy, use, modify, sell and
+//  distribute this software is granted provided this copyright notice appears
+//  in all copies. This software is provided "as is" without express or implied
+//  warranty, and with no claim as to its suitability for any purpose.
+
+//  See http://www.boost.org for most recent version.
+
+//  STLPort standard library config:
+
+#if !defined(__SGI_STL_PORT) && !defined(_STLPORT_VERSION)
+#  include <utility>
+#  if !defined(__SGI_STL_PORT) && !defined(_STLPORT_VERSION)
+#      error "This is not STLPort!"
+#  endif
+#endif
+
+//
+// __STL_STATIC_CONST_INIT_BUG implies BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
+// for versions prior to 4.1(beta)
+//
+#if (defined(__STL_STATIC_CONST_INIT_BUG) || defined(_STLP_STATIC_CONST_INIT_BUG)) && (__SGI_STL_PORT <= 0x400)
+#  define BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
+#endif
+
+//
+// If STLport thinks that there is no partial specialisation, then there is no
+// std::iterator traits:
+//
+#if !(defined(_STLP_CLASS_PARTIAL_SPECIALIZATION) || defined(__STL_CLASS_PARTIAL_SPECIALIZATION))
+#  define BOOST_NO_STD_ITERATOR_TRAITS
+#endif
+
+//
+// No new style iostreams on GCC without STLport's iostreams enabled:
+//
+#if (defined(__GNUC__) && (__GNUC__ < 3)) && !(defined(__SGI_STL_OWN_IOSTREAMS) || defined(_STLP_OWN_IOSTREAMS))
+#  define BOOST_NO_STRINGSTREAM
+#endif
+
+//
+// No new iostreams implies no std::locale, and no std::stringstream:
+//
+#if defined(__STL_NO_IOSTREAMS) || defined(__STL_NO_NEW_IOSTREAMS) || defined(_STLP_NO_IOSTREAMS) || defined(_STLP_NO_NEW_IOSTREAMS)
+#  define BOOST_NO_STD_LOCALE
+#  define BOOST_NO_STRINGSTREAM
+#endif
+
+//
+// Without member template support enabled, their are no template
+// iterate constructors, and no std::allocator:
+//
+#if !(defined(__STL_MEMBER_TEMPLATES) || defined(_STLP_MEMBER_TEMPLATES))
+#  define BOOST_NO_TEMPLATED_ITERATOR_CONSTRUCTORS
+#  define BOOST_NO_STD_ALLOCATOR
+#endif
+
+#if !defined(_STLP_MEMBER_TEMPLATE_CLASSES)
+#  define BOOST_NO_STD_ALLOCATOR
+#endif
+
+//
+// We always have SGI style hash_set, hash_map, and slist:
+//
+#define BOOST_HAS_HASH
+#define BOOST_HAS_SLIST
+
+//
+// STLport does a good job of importing names into namespace std::,
+// but doesn't always get them all, define BOOST_NO_STDC_NAMESPACE, since our
+// workaround does not conflict with STLports:
+//
+#if defined(__STL_IMPORT_VENDOR_CSTD) || defined(__STL_USE_OWN_NAMESPACE) || defined(_STLP_IMPORT_VENDOR_CSTD) || defined(_STLP_USE_OWN_NAMESPACE)
+#  define BOOST_NO_STDC_NAMESPACE
+#endif
+
+//
+// std::reverse_iterate behaves like VC6's under some circumstances:
+//
+#if defined (_STLP_USE_OLD_HP_ITERATOR_QUERIES)  || defined (__STL_USE_OLD_HP_ITERATOR_QUERIES)\
+ || (!defined ( _STLP_CLASS_PARTIAL_SPECIALIZATION ) && !defined ( __STL_CLASS_PARTIAL_SPECIALIZATION ))
+// disable this for now, it causes too many problems, we need a better
+// fix for broken reverse iterators:
+// #  define BOOST_MSVC_STD_ITERATOR
+#endif
+
+//
+// std::use_facet may be non-standard, uses a class instead:
+//
+#if defined(__STL_NO_EXPLICIT_FUNCTION_TMPL_ARGS) || defined(_STLP_NO_EXPLICIT_FUNCTION_TMPL_ARGS)
+#  define BOOST_NO_STD_USE_FACET
+#  define BOOST_HAS_STLP_USE_FACET
+#endif
+
+//
+// If STLport thinks there are no wide functions, <cwchar> etc. is not working.
+//
+#if defined(_STLP_NO_NATIVE_WIDE_FUNCTIONS)
+#  define BOOST_NO_CWCHAR
+#  define BOOST_NO_CWTYPE
+#endif
+
+
+#define BOOST_STDLIB "STLPort standard library version " BOOST_STRINGIZE(__SGI_STL_PORT)
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/boost/boost/config/stdlib/vacpp.hpp	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,13 @@
+//  (C) Copyright Boost.org 2001. Permission to copy, use, modify, sell and
+//  distribute this software is granted provided this copyright notice appears
+//  in all copies. This software is provided "as is" without express or implied
+//  warranty, and with no claim as to its suitability for any purpose.
+
+//  See http://www.boost.org for most recent version.
+
+#define BOOST_HAS_MACRO_USE_FACET
+#define BOOST_NO_STD_ALLOCATOR
+
+#define BOOST_STDLIB "Visual Age default standard library"
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/boost/boost/config/suffix.hpp	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,311 @@
+//  Boost config.hpp configuration header file  ------------------------------//
+
+//  (C) Copyright Boost.org 2001. Permission to copy, use, modify, sell and
+//  distribute this software is granted provided this copyright notice appears
+//  in all copies. This software is provided "as is" without express or implied
+//  warranty, and with no claim as to its suitability for any purpose.
+
+//  See http://www.boost.org for most recent version.
+
+//  Boost config.hpp policy and rationale documentation has been moved to
+//  http://www.boost.org/libs/config
+//
+//  This file is intended to be stable, and relatively unchanging.
+//  It should contain boilerplate code only - no compiler specific
+//  code unless it is unavoidable - no changes unless unavoidable.
+
+#ifndef BOOST_CONFIG_SUFFIX_HPP
+#define BOOST_CONFIG_SUFFIX_HPP
+
+# ifndef BOOST_DECL
+#   define BOOST_DECL  // default for compilers not needing this decoration.
+# endif
+
+//
+// Assume any extensions are in namespace std:: unless stated otherwise:
+//
+#  ifndef BOOST_STD_EXTENSION_NAMESPACE
+#    define BOOST_STD_EXTENSION_NAMESPACE std
+#  endif
+
+//
+// If cv-qualified specializations are not allowed, then neither are cv-void ones:
+//
+#  if defined(BOOST_NO_CV_SPECIALIZATIONS) \
+      && !defined(BOOST_NO_CV_VOID_SPECIALIZATIONS)
+#     define BOOST_NO_CV_VOID_SPECIALIZATIONS
+#  endif
+
+//
+// If there is no numeric_limits template, then it can't have any compile time
+// constants either!
+//
+#  if defined(BOOST_NO_LIMITS) \
+      && !defined(BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS)
+#     define BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
+#  endif
+
+//
+// if member templates are supported then so is the
+// VC6 subset of member templates:
+//
+#  if !defined(BOOST_NO_MEMBER_TEMPLATES) \
+       && !defined(BOOST_MSVC6_MEMBER_TEMPLATES)
+#     define BOOST_MSVC6_MEMBER_TEMPLATES
+#  endif
+
+//
+// Without partial specialization, std::iterator_traits can't work:
+//
+#  if defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) \
+      && !defined(BOOST_NO_STD_ITERATOR_TRAITS)
+#     define BOOST_NO_STD_ITERATOR_TRAITS
+#  endif
+
+//
+// Without member template support, we can't have template constructors
+// in the standard library either:
+//
+#  if defined(BOOST_NO_MEMBER_TEMPLATES) \
+      && !defined(BOOST_MSVC6_MEMBER_TEMPLATES) \
+      && !defined(BOOST_NO_TEMPLATED_ITERATOR_CONSTRUCTORS)
+#     define BOOST_NO_TEMPLATED_ITERATOR_CONSTRUCTORS
+#  endif
+
+//
+// Without member template support, we can't have a conforming
+// std::allocator template either:
+//
+#  if defined(BOOST_NO_MEMBER_TEMPLATES) \
+      && !defined(BOOST_MSVC6_MEMBER_TEMPLATES) \
+      && !defined(BOOST_NO_STD_ALLOCATOR)
+#     define BOOST_NO_STD_ALLOCATOR
+#  endif
+
+//
+// We can't have a working std::use_facet if there is no std::locale:
+//
+#  if defined(BOOST_NO_STD_LOCALE) && !defined(BOOST_NO_STD_USE_FACET)
+#     define BOOST_NO_STD_USE_FACET
+#  endif
+
+//
+// We can't have a std::messages facet if there is no std::locale:
+//
+#  if defined(BOOST_NO_STD_LOCALE) && !defined(BOOST_NO_STD_MESSAGES)
+#     define BOOST_NO_STD_MESSAGES
+#  endif
+
+//
+// We can't have a <cwctype> if there is no <cwchar>:
+//
+#  if defined(BOOST_NO_CWCHAR) && !defined(BOOST_NO_CWCTYPE)
+#     define BOOST_NO_CWCTYPE
+#  endif
+
+//
+// We can't have a swprintf if there is no <cwchar>:
+//
+#  if defined(BOOST_NO_CWCHAR) && !defined(BOOST_NO_SWPRINTF)
+#     define BOOST_NO_SWPRINTF
+#  endif
+
+//
+// If the platform claims to be Unix, then it had better behave like Unix!
+//
+#  if defined(unix) \
+      || defined(__unix) \
+      || defined(_XOPEN_SOURCE) \
+      || defined(_POSIX_SOURCE)
+
+#     ifndef BOOST_HAS_UNISTD_H
+#        define BOOST_HAS_UNISTD_H
+#     endif
+#  endif
+
+//
+// If we have a <unistd.h> then some options can be deduced from it:
+//
+#  ifdef BOOST_HAS_UNISTD_H
+#     include <boost/config/posix_features.hpp>
+#  endif
+
+//
+// Turn on threading support if the compiler thinks that it's in
+// multithreaded mode.  We put this here because there are only a
+// limited number of macros that identify this (if there's any missing
+// from here then add to the appropriate compiler section):
+//
+#if (defined(__MT__) || defined(_MT) || defined(_REENTRANT) \
+    || defined(_PTHREADS)) && !defined(BOOST_HAS_THREADS)
+#  define BOOST_HAS_THREADS
+#endif
+
+//
+// Turn threading support off if BOOST_DISABLE_THREADS is defined:
+//
+#if defined(BOOST_DISABLE_THREADS) && defined(BOOST_HAS_THREADS)
+#  undef BOOST_HAS_THREADS
+#endif
+
+//
+// Turn threading support off if we don't recognise the threading API:
+//
+#if defined(BOOST_HAS_THREADS) && !defined(BOOST_HAS_PTHREADS)\
+      && !defined(BOOST_HAS_WINTHREADS) && !defined(BOOST_HAS_BETHREADS)
+#  undef BOOST_HAS_THREADS
+#endif
+
+//
+// If the compiler claims to be C99 conformant, then it had better
+// have a <stdint.h>:
+//
+#  if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901)
+#     define BOOST_HAS_STDINT_H
+#  endif
+
+//
+// Define BOOST_NO_SLIST and BOOST_NO_HASH if required.
+// Note that this is for backwards compatibility only.
+//
+#  ifndef BOOST_HAS_SLIST
+#     define BOOST_NO_SLIST
+#  endif
+
+#  ifndef BOOST_HAS_HASH
+#     define BOOST_NO_HASH
+#  endif
+
+//  BOOST_NO_STDC_NAMESPACE workaround  --------------------------------------//
+//  Because std::size_t usage is so common, even in boost headers which do not
+//  otherwise use the C library, the <cstddef> workaround is included here so
+//  that ugly workaround code need not appear in many other boost headers.
+//  NOTE WELL: This is a workaround for non-conforming compilers; <cstddef> 
+//  must still be #included in the usual places so that <cstddef> inclusion
+//  works as expected with standard conforming compilers.  The resulting
+//  double inclusion of <cstddef> is harmless.
+
+# ifdef BOOST_NO_STDC_NAMESPACE
+#   include <cstddef>
+    namespace std { using ::ptrdiff_t; using ::size_t; }
+# endif
+
+//  BOOST_NO_STD_MIN_MAX workaround  -----------------------------------------//
+
+#  ifdef BOOST_NO_STD_MIN_MAX
+
+namespace std {
+  template <class _Tp>
+  inline const _Tp& min(const _Tp& __a, const _Tp& __b) {
+    return __b < __a ? __b : __a;
+  }
+  template <class _Tp>
+  inline const _Tp& max(const _Tp& __a, const _Tp& __b) {
+    return  __a < __b ? __b : __a;
+  }
+#     ifdef BOOST_MSVC
+  inline long min(long __a, long __b) {
+    return __b < __a ? __b : __a;
+  }
+  inline long max(long __a, long __b) {
+    return  __a < __b ? __b : __a;
+  }
+#     endif
+}
+
+#  endif
+
+// BOOST_STATIC_CONSTANT workaround --------------------------------------- //
+// On compilers which don't allow in-class initialization of static integral
+// constant members, we must use enums as a workaround if we want the constants
+// to be available at compile-time. This macro gives us a convenient way to
+// declare such constants.
+
+#  ifdef BOOST_NO_INCLASS_MEMBER_INITIALIZATION
+#       define BOOST_STATIC_CONSTANT(type, assignment) enum { assignment }
+#  else
+#     define BOOST_STATIC_CONSTANT(type, assignment) static const type assignment
+#  endif
+
+// BOOST_USE_FACET workaround ----------------------------------------------//
+// When the standard library does not have a conforming std::use_facet there
+// are various workarounds available, but they differ from library to library.
+// This macro provides a consistent way to access a locale's facets.
+// Usage:
+//    replace
+//       std::use_facet<Type>(loc);
+//    with
+//       BOOST_USE_FACET(Type, loc);
+//    Note do not add a std:: prefix to the front of BOOST_USE_FACET!
+
+#if defined(BOOST_NO_STD_USE_FACET)
+#  ifdef BOOST_HAS_TWO_ARG_USE_FACET
+#     define BOOST_USE_FACET(Type, loc) std::use_facet(loc, static_cast<Type const*>(0))
+#  elif defined(BOOST_HAS_MACRO_USE_FACET)
+#     define BOOST_USE_FACET(Type, loc) std::_USE(loc, Type)
+#  elif defined(BOOST_HAS_STLP_USE_FACET)
+#     define BOOST_USE_FACET(Type, loc) (*std::_Use_facet<Type >(loc))
+#  endif
+#else
+#  define BOOST_USE_FACET(Type, loc) std::use_facet< Type >(loc)
+#endif
+
+// BOOST_NESTED_TEMPLATE workaround ------------------------------------------//
+// Member templates are supported by some compilers even though they can't use
+// the A::template member<U> syntax, as a workaround replace:
+//
+// typedef typename A::template rebind<U> binder;
+//
+// with:
+//
+// typedef typename A::BOOST_NESTED_TEMPLATE rebind<U> binder;
+
+#ifndef BOOST_NO_MEMBER_TEMPLATE_KEYWORD
+#  define BOOST_NESTED_TEMPLATE template
+#else
+#  define BOOST_NESTED_TEMPLATE
+#endif
+
+// ---------------------------------------------------------------------------//
+
+//
+// Helper macro BOOST_STRINGIZE:
+// Converts the parameter X to a string after macro replacement
+// on X has been performed.
+//
+#define BOOST_STRINGIZE(X) BOOST_DO_STRINGIZE(X)
+#define BOOST_DO_STRINGIZE(X) #X
+
+//
+// Helper macro BOOST_JOIN:
+// The following piece of macro magic joins the two 
+// arguments together, even when one of the arguments is
+// itself a macro (see 16.3.1 in C++ standard).  The key
+// is that macro expansion of macro arguments does not
+// occur in BOOST_DO_JOIN2 but does in BOOST_DO_JOIN.
+//
+#define BOOST_JOIN( X, Y ) BOOST_DO_JOIN( X, Y )
+#define BOOST_DO_JOIN( X, Y ) BOOST_DO_JOIN2(X,Y)
+#define BOOST_DO_JOIN2( X, Y ) X##Y
+
+//
+// Set some default values for compiler/library/platform names.
+// These are for debugging config setup only:
+//
+#  ifndef BOOST_COMPILER
+#     define BOOST_COMPILER "Unknown ISO C++ Compiler"
+#  endif
+#  ifndef BOOST_STDLIB
+#     define BOOST_STDLIB "Unknown ISO standard library"
+#  endif
+#  ifndef BOOST_PLATFORM
+#     if defined(unix) || defined(__unix) || defined(_XOPEN_SOURCE) \
+         || defined(_POSIX_SOURCE)
+#        define BOOST_PLATFORM "Generic Unix"
+#     else
+#        define BOOST_PLATFORM "Unknown"
+#     endif
+#  endif
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/boost/boost/config/user.hpp	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,58 @@
+//  (C) Copyright Boost.org 2001.
+//  Do not check in modified versions of this file,
+//  This file may be customized by the end user, but not by boost.
+
+//
+//  Use this file to define a site and compiler specific
+//  configuration policy:
+//
+
+// define this to locate a compiler config file:
+// #define BOOST_COMPILER_CONFIG <myheader>
+
+// define this to locate a stdlib config file:
+// #define BOOST_STDLIB_CONFIG   <myheader>
+
+// define this to locate a platform config file:
+// #define BOOST_PLATFORM_CONFIG <myheader>
+
+// define this to disable compiler config,
+// use if your compiler config has nothing to set:
+// #define BOOST_NO_COMPILER_CONFIG
+
+// define this to disable stdlib config,
+// use if your stdlib config has nothing to set:
+// #define BOOST_NO_STDLIB_CONFIG
+
+// define this to disable platform config,
+// use if your platform config has nothing to set:
+// #define BOOST_NO_PLATFORM_CONFIG
+
+// define this to disable all config options,
+// excluding the user config.  Use if your
+// setup is fully ISO compliant, and has no
+// useful extensions, or for autoconf generated
+// setups:
+// #define BOOST_NO_CONFIG
+
+// define this to make the config "optimistic"
+// about unknown compiler versions.  Normally
+// unknown compiler versions are assumed to have
+// all the defects of the last known version, however
+// setting this flag, causes the config to assume
+// that unknown compiler versions are fully conformant
+// with the standard:
+// #define BOOST_STRICT_CONFIG
+
+// define this to cause the config to halt compilation
+// with an #error if it encounters anything unknown --
+// either an unknown compiler version or an unknown
+// compiler/platform/library:
+// #define BOOST_ASSERT_CONFIG
+
+
+// define if you want to disable threading support, even
+// when available:
+// #define BOOST_DISABLE_THREADS
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/boost/boost/smart_ptr.hpp	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,402 @@
+//  Boost smart_ptr.hpp header file  -----------------------------------------//
+
+//  (C) Copyright Greg Colvin and Beman Dawes 1998, 1999. Permission to copy,
+//  use, modify, sell and distribute this software is granted provided this
+//  copyright notice appears in all copies. This software is provided "as is"
+//  without express or implied warranty, and with no claim as to its
+//  suitability for any purpose.
+
+//  See http://www.boost.org for most recent version including documentation.
+
+//  Revision History
+//   6 Jul 01  Reorder shared_ptr code so VC++ 6 member templates work, allowing
+//             polymorphic pointers to now work with that compiler (Gary Powell)
+//  21 May 01  Require complete type where incomplete type is unsafe.
+//             (suggested by Vladimir Prus)
+//  21 May 01  operator= fails if operand transitively owned by *this, as in a
+//             linked list (report by Ken Johnson, fix by Beman Dawes)
+//  21 Jan 01  Suppress some useless warnings with MSVC (David Abrahams)
+//  19 Oct 00  Make shared_ptr ctor from auto_ptr explicit. (Robert Vugts) 
+//  24 Jul 00  Change throw() to // never throws.  See lib guidelines
+//             Exception-specification rationale. (Beman Dawes)
+//  22 Jun 00  Remove #if continuations to fix GCC 2.95.2 problem (Beman Dawes)
+//   1 Feb 00  Additional shared_ptr BOOST_NO_MEMBER_TEMPLATES workarounds
+//             (Dave Abrahams)
+//  31 Dec 99  Condition tightened for no member template friend workaround
+//             (Dave Abrahams)
+//  30 Dec 99  Moved BOOST_NMEMBER_TEMPLATES compatibility code to config.hpp
+//             (Dave Abrahams)
+//  30 Nov 99  added operator ==, operator !=, and std::swap and std::less
+//             specializations for shared types (Darin Adler)
+//  11 Oct 99  replaced op[](int) with op[](std::size_t) (Ed Brey, Valentin
+//             Bonnard), added shared_ptr workaround for no member template
+//             friends (Matthew Langston)
+//  25 Sep 99  added shared_ptr::swap and shared_array::swap (Luis Coelho).
+//  20 Jul 99  changed name to smart_ptr.hpp, #include <boost/config.hpp>,
+//             #include <boost/utility.hpp> and use boost::noncopyable
+//  17 May 99  remove scoped_array and shared_array operator*() as
+//             unnecessary (Beman Dawes)
+//  14 May 99  reorder code so no effects when bad_alloc thrown (Abrahams/Dawes)
+//  13 May 99  remove certain throw() specifiers to avoid generated try/catch
+//             code cost (Beman Dawes)
+//  11 May 99  get() added, conversion to T* placed in macro guard (Valentin
+//             Bonnard, Dave Abrahams, and others argued for elimination
+//             of the automatic conversion)
+//  28 Apr 99  #include <memory> fix (Valentin Bonnard)
+//  28 Apr 99  rename transfer() to share() for clarity (Dave Abrahams)
+//  28 Apr 99  remove unsafe shared_array template conversions(Valentin Bonnard)
+//  28 Apr 99  p(r) changed to p(r.px) for clarity (Dave Abrahams)
+//  21 Apr 99  reset() self assignment fix (Valentin Bonnard)
+//  21 Apr 99  dispose() provided to improve clarity (Valentin Bonnard)
+//  27 Apr 99  leak when new throws fixes (Dave Abrahams)
+//  21 Oct 98  initial Version (Greg Colvin/Beman Dawes)
+
+#ifndef BOOST_SMART_PTR_HPP
+#define BOOST_SMART_PTR_HPP
+
+#include <boost/config.hpp>   // for broken compiler workarounds
+#include <cstddef>            // for std::size_t
+#include <memory>             // for std::auto_ptr
+#include <algorithm>          // for std::swap
+#include <boost/utility.hpp>  // for boost::noncopyable, checked_delete, checked_array_delete
+#include <functional>         // for std::less
+#include <boost/static_assert.hpp> // for BOOST_STATIC_ASSERT
+
+#ifdef BOOST_MSVC  // moved here to work around VC++ compiler crash
+# pragma warning(push)
+# pragma warning(disable:4284) // return type for 'identifier::operator->' is not a UDT or reference to a UDT. Will produce errors if applied using infix notation
+#endif    
+
+namespace boost {
+
+//  scoped_ptr  --------------------------------------------------------------//
+
+//  scoped_ptr mimics a built-in pointer except that it guarantees deletion
+//  of the object pointed to, either on destruction of the scoped_ptr or via
+//  an explicit reset().  scoped_ptr is a simple solution for simple needs;
+//  see shared_ptr (below) or std::auto_ptr if your needs are more complex.
+
+template<typename T> class scoped_ptr : noncopyable {
+
+  T* ptr;
+
+ public:
+  typedef T element_type;
+
+  explicit scoped_ptr( T* p=0 ) : ptr(p) {}  // never throws
+  ~scoped_ptr()                 { checked_delete(ptr); }
+  void reset( T* p=0 )          { if ( ptr != p ) { checked_delete(ptr); ptr = p; } }
+  T& operator*() const          { return *ptr; }  // never throws
+  T* operator->() const         { return ptr; }  // never throws
+  T* get() const                { return ptr; }  // never throws
+#ifdef BOOST_SMART_PTR_CONVERSION
+  // get() is safer! Define BOOST_SMART_PTR_CONVERSION at your own risk!
+  operator T*() const           { return ptr; }  // never throws 
+#endif
+  };  // scoped_ptr
+
+//  scoped_array  ------------------------------------------------------------//
+
+//  scoped_array extends scoped_ptr to arrays. Deletion of the array pointed to
+//  is guaranteed, either on destruction of the scoped_array or via an explicit
+//  reset(). See shared_array or std::vector if your needs are more complex.
+
+template<typename T> class scoped_array : noncopyable {
+
+  T* ptr;
+
+ public:
+  typedef T element_type;
+
+  explicit scoped_array( T* p=0 ) : ptr(p) {}  // never throws
+  ~scoped_array()                    { checked_array_delete(ptr); }
+
+  void reset( T* p=0 )               { if ( ptr != p )
+                                         {checked_array_delete(ptr); ptr=p;} }
+
+  T* get() const                     { return ptr; }  // never throws
+#ifdef BOOST_SMART_PTR_CONVERSION
+  // get() is safer! Define BOOST_SMART_PTR_CONVERSION at your own risk!
+  operator T*() const                { return ptr; }  // never throws
+#else 
+  T& operator[](std::size_t i) const { return ptr[i]; }  // never throws
+#endif
+  };  // scoped_array
+
+//  shared_ptr  --------------------------------------------------------------//
+
+//  An enhanced relative of scoped_ptr with reference counted copy semantics.
+//  The object pointed to is deleted when the last shared_ptr pointing to it
+//  is destroyed or reset.
+
+template<typename T> class shared_ptr {
+  public:
+   typedef T element_type;
+
+   explicit shared_ptr(T* p =0) : px(p) {
+      try { pn = new long(1); }  // fix: prevent leak if new throws
+      catch (...) { checked_delete(p); throw; } 
+   }
+
+   ~shared_ptr() { dispose(); }
+
+#if !defined( BOOST_NO_MEMBER_TEMPLATES ) || defined (BOOST_MSVC6_MEMBER_TEMPLATES)
+   template<typename Y>
+      shared_ptr(const shared_ptr<Y>& r) : px(r.px) {  // never throws 
+         ++*(pn = r.pn); 
+      }
+#ifndef BOOST_NO_AUTO_PTR
+   template<typename Y>
+      explicit shared_ptr(std::auto_ptr<Y>& r) { 
+         pn = new long(1); // may throw
+         px = r.release(); // fix: moved here to stop leak if new throws
+      }
+#endif 
+
+   template<typename Y>
+      shared_ptr& operator=(const shared_ptr<Y>& r) { 
+         share(r.px,r.pn);
+         return *this;
+      }
+
+#ifndef BOOST_NO_AUTO_PTR
+   template<typename Y>
+      shared_ptr& operator=(std::auto_ptr<Y>& r) {
+         // code choice driven by guarantee of "no effect if new throws"
+         if (*pn == 1) { checked_delete(px); }
+         else { // allocate new reference counter
+           long * tmp = new long(1); // may throw
+           --*pn; // only decrement once danger of new throwing is past
+           pn = tmp;
+         } // allocate new reference counter
+         px = r.release(); // fix: moved here so doesn't leak if new throws 
+         return *this;
+      }
+#endif
+#else
+#ifndef BOOST_NO_AUTO_PTR
+      explicit shared_ptr(std::auto_ptr<T>& r) { 
+         pn = new long(1); // may throw
+         px = r.release(); // fix: moved here to stop leak if new throws
+      } 
+
+      shared_ptr& operator=(std::auto_ptr<T>& r) {
+         // code choice driven by guarantee of "no effect if new throws"
+         if (*pn == 1) { checked_delete(px); }
+         else { // allocate new reference counter
+           long * tmp = new long(1); // may throw
+           --*pn; // only decrement once danger of new throwing is past
+           pn = tmp;
+         } // allocate new reference counter
+         px = r.release(); // fix: moved here so doesn't leak if new throws 
+         return *this;
+      }
+#endif
+#endif
+
+   // The assignment operator and the copy constructor must come after
+   // the templated versions for MSVC6 to work. (Gary Powell)
+   shared_ptr(const shared_ptr& r) : px(r.px) { ++*(pn = r.pn); }  // never throws
+
+   shared_ptr& operator=(const shared_ptr& r) {
+      share(r.px,r.pn);
+      return *this;
+   }
+
+   void reset(T* p=0) {
+      if ( px == p ) return;  // fix: self-assignment safe
+      if (--*pn == 0) { checked_delete(px); }
+      else { // allocate new reference counter
+        try { pn = new long; }  // fix: prevent leak if new throws
+        catch (...) {
+          ++*pn;  // undo effect of --*pn above to meet effects guarantee 
+          checked_delete(p);
+          throw;
+        } // catch
+      } // allocate new reference counter
+      *pn = 1;
+      px = p;
+   } // reset
+
+   T& operator*() const          { return *px; }  // never throws
+   T* operator->() const         { return px; }  // never throws
+   T* get() const                { return px; }  // never throws
+ #ifdef BOOST_SMART_PTR_CONVERSION
+   // get() is safer! Define BOOST_SMART_PTR_CONVERSION at your own risk!
+   operator T*() const           { return px; }  // never throws 
+ #endif
+
+   long use_count() const        { return *pn; }  // never throws
+   bool unique() const           { return *pn == 1; }  // never throws
+
+   void swap(shared_ptr<T>& other)  // never throws
+     { std::swap(px,other.px); std::swap(pn,other.pn); }
+
+// Tasteless as this may seem, making all members public allows member templates
+// to work in the absence of member template friends. (Matthew Langston)
+// Don't split this line into two; that causes problems for some GCC 2.95.2 builds
+#if ( defined(BOOST_NO_MEMBER_TEMPLATES) && !defined(BOOST_MSVC6_MEMBER_TEMPLATES) ) || !defined( BOOST_NO_MEMBER_TEMPLATE_FRIENDS )
+   private:
+#endif
+
+   T*     px;     // contained pointer
+   long*  pn;     // ptr to reference counter
+
+// Don't split this line into two; that causes problems for some GCC 2.95.2 builds
+#if !defined( BOOST_NO_MEMBER_TEMPLATES ) && !defined( BOOST_NO_MEMBER_TEMPLATE_FRIENDS )
+   template<typename Y> friend class shared_ptr;
+#endif
+
+   void dispose() { if (--*pn == 0) { checked_delete(px); delete pn; } }
+
+   void share(T* rpx, long* rpn) {
+      if (pn != rpn) { // Q: why not px != rpx? A: fails when both == 0
+         ++*rpn; // done before dispose() in case rpn transitively
+                 // dependent on *this (bug reported by Ken Johnson)
+         dispose();
+         px = rpx;
+         pn = rpn;
+      }
+   } // share
+};  // shared_ptr
+
+template<typename T, typename U>
+  inline bool operator==(const shared_ptr<T>& a, const shared_ptr<U>& b)
+    { return a.get() == b.get(); }
+
+template<typename T, typename U>
+  inline bool operator!=(const shared_ptr<T>& a, const shared_ptr<U>& b)
+    { return a.get() != b.get(); }
+
+//  shared_array  ------------------------------------------------------------//
+
+//  shared_array extends shared_ptr to arrays.
+//  The array pointed to is deleted when the last shared_array pointing to it
+//  is destroyed or reset.
+
+template<typename T> class shared_array {
+  public:
+   typedef T element_type;
+
+   explicit shared_array(T* p =0) : px(p) {
+      try { pn = new long(1); }  // fix: prevent leak if new throws
+      catch (...) { checked_array_delete(p); throw; } 
+   }
+
+   shared_array(const shared_array& r) : px(r.px)  // never throws
+      { ++*(pn = r.pn); }
+
+   ~shared_array() { dispose(); }
+
+   shared_array& operator=(const shared_array& r) {
+      if (pn != r.pn) { // Q: why not px != r.px? A: fails when both px == 0
+         ++*r.pn; // done before dispose() in case r.pn transitively
+                  // dependent on *this (bug reported by Ken Johnson)
+         dispose();
+         px = r.px;
+         pn = r.pn;
+      }
+      return *this;
+   } // operator=
+
+   void reset(T* p=0) {
+      if ( px == p ) return;  // fix: self-assignment safe
+      if (--*pn == 0) { checked_array_delete(px); }
+      else { // allocate new reference counter
+        try { pn = new long; }  // fix: prevent leak if new throws
+        catch (...) {
+          ++*pn;  // undo effect of --*pn above to meet effects guarantee 
+          checked_array_delete(p);
+          throw;
+        } // catch
+      } // allocate new reference counter
+      *pn = 1;
+      px = p;
+   } // reset
+
+   T* get() const                     { return px; }  // never throws
+ #ifdef BOOST_SMART_PTR_CONVERSION
+   // get() is safer! Define BOOST_SMART_PTR_CONVERSION at your own risk!
+   operator T*() const                { return px; }  // never throws
+ #else 
+   T& operator[](std::size_t i) const { return px[i]; }  // never throws
+ #endif
+
+   long use_count() const             { return *pn; }  // never throws
+   bool unique() const                { return *pn == 1; }  // never throws
+
+   void swap(shared_array<T>& other)  // never throws
+     { std::swap(px,other.px); std::swap(pn,other.pn); }
+
+  private:
+
+   T*     px;     // contained pointer
+   long*  pn;     // ptr to reference counter
+
+   void dispose() { if (--*pn == 0) { checked_array_delete(px); delete pn; } }
+
+};  // shared_array
+
+template<typename T>
+  inline bool operator==(const shared_array<T>& a, const shared_array<T>& b)
+    { return a.get() == b.get(); }
+
+template<typename T>
+  inline bool operator!=(const shared_array<T>& a, const shared_array<T>& b)
+    { return a.get() != b.get(); }
+
+} // namespace boost
+
+//  specializations for things in namespace std  -----------------------------//
+
+#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
+
+namespace std {
+
+// Specialize std::swap to use the fast, non-throwing swap that's provided
+// as a member function instead of using the default algorithm which creates
+// a temporary and uses assignment.
+
+template<typename T>
+  inline void swap(boost::shared_ptr<T>& a, boost::shared_ptr<T>& b)
+    { a.swap(b); }
+
+template<typename T>
+  inline void swap(boost::shared_array<T>& a, boost::shared_array<T>& b)
+    { a.swap(b); }
+
+// Specialize std::less so we can use shared pointers and arrays as keys in
+// associative collections.
+
+// It's still a controversial question whether this is better than supplying
+// a full range of comparison operators (<, >, <=, >=).
+
+template<typename T>
+  struct less< boost::shared_ptr<T> >
+    : binary_function<boost::shared_ptr<T>, boost::shared_ptr<T>, bool>
+  {
+    bool operator()(const boost::shared_ptr<T>& a,
+        const boost::shared_ptr<T>& b) const
+      { return less<T*>()(a.get(),b.get()); }
+  };
+
+template<typename T>
+  struct less< boost::shared_array<T> >
+    : binary_function<boost::shared_array<T>, boost::shared_array<T>, bool>
+  {
+    bool operator()(const boost::shared_array<T>& a,
+        const boost::shared_array<T>& b) const
+      { return less<T*>()(a.get(),b.get()); }
+  };
+
+} // namespace std
+
+#endif  // ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
+
+#ifdef BOOST_MSVC
+# pragma warning(pop)
+#endif    
+
+#endif  // BOOST_SMART_PTR_HPP
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/boost/boost/static_assert.hpp	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,86 @@
+//  (C) Copyright John Maddock 2000.
+//  Permission to copy, use, modify, sell and
+//  distribute this software is granted provided this copyright notice appears
+//  in all copies. This software is provided "as is" without express or implied
+//  warranty, and with no claim as to its suitability for any purpose.
+
+//  See http://www.boost.org for most recent version including documentation.
+
+/*
+ Revision history:
+ 	02 August 2000
+ 		Initial version.
+*/
+
+#ifndef BOOST_STATIC_ASSERT_HPP
+#define BOOST_STATIC_ASSERT_HPP
+
+#include <boost/config.hpp>
+
+#ifdef __BORLANDC__
+//
+// workaround for buggy integral-constant expression support:
+#define BOOST_BUGGY_INTEGRAL_CONSTANT_EXPRESSIONS
+#endif
+
+namespace boost{
+
+// HP aCC cannot deal with missing names for template value parameters
+template <bool x> struct STATIC_ASSERTION_FAILURE;
+
+template <> struct STATIC_ASSERTION_FAILURE<true>{};
+
+// HP aCC cannot deal with missing names for template value parameters
+template<int x> struct static_assert_test{};
+
+}
+
+//
+// Implicit instantiation requires that all member declarations be
+// instantiated, but that the definitions are *not* instantiated.
+//
+// It's not particularly clear how this applies to enum's or typedefs;
+// both are described as declarations [7.1.3] and [7.2] in the standard,
+// however some compilers use "delayed evaluation" of one or more of
+// these when implicitly instantiating templates.  We use typedef declarations
+// by default, but try defining BOOST_USE_ENUM_STATIC_ASSERT if the enum
+// version gets better results from your compiler...
+//
+// Implementation:
+// Both of these versions rely on sizeof(incomplete_type) generating an error
+// message containing the name of the incomplete type.  We use
+// "STATIC_ASSERTION_FAILURE" as the type name here to generate
+// an eye catching error message.  The result of the sizeof expression is either
+// used as an enum initialiser, or as a template argument depending which version
+// is in use...
+// Note that the argument to the assert is explicitly cast to bool using old-
+// style casts: too many compilers currently have problems with static_cast
+// when used inside integral constant expressions.
+//
+#if !defined(BOOST_BUGGY_INTEGRAL_CONSTANT_EXPRESSIONS) && !defined(__MWERKS__)
+#ifndef BOOST_MSVC
+#define BOOST_STATIC_ASSERT( B ) \
+   typedef ::boost::static_assert_test<\
+      sizeof(::boost::STATIC_ASSERTION_FAILURE< (bool)( B ) >)>\
+         BOOST_JOIN(boost_static_assert_typedef_, __LINE__)
+#else
+// __LINE__ macro broken when -ZI is used see Q199057
+// fortunately MSVC ignores duplicate typedef's.
+#define BOOST_STATIC_ASSERT( B ) \
+   typedef ::boost::static_assert_test<\
+      sizeof(::boost::STATIC_ASSERTION_FAILURE< (bool)( B ) >)\
+      > boost_static_assert_typedef_
+#endif
+#else
+// alternative enum based implementation:
+#define BOOST_STATIC_ASSERT( B ) \
+   enum { BOOST_JOIN(boost_static_assert_enum_, __LINE__) \
+      = sizeof(::boost::STATIC_ASSERTION_FAILURE< (bool)( B ) >) }
+#endif
+
+
+#endif // BOOST_STATIC_ASSERT_HPP
+
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/boost/boost/utility.hpp	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,86 @@
+//  boost utility.hpp header file  -------------------------------------------//
+
+//  (C) Copyright boost.org 1999. Permission to copy, use, modify, sell
+//  and distribute this software is granted provided this copyright
+//  notice appears in all copies. This software is provided "as is" without
+//  express or implied warranty, and with no claim as to its suitability for
+//  any purpose.
+
+//  See http://www.boost.org for most recent version including documentation.
+
+//  Classes appear in alphabetical order
+
+#ifndef BOOST_UTILITY_HPP
+#define BOOST_UTILITY_HPP
+
+#include <boost/config.hpp>        // broken compiler workarounds
+#include <boost/static_assert.hpp>
+
+// certain headers are part of the <utility.hpp> interface
+#include <boost/utility/base_from_member.hpp>  
+ 
+#include <cstddef>                 // for size_t
+#include <utility>                 // for std::pair
+
+namespace boost
+{
+//  checked_delete() and checked_array_delete()  -----------------------------//
+
+    // verify that types are complete for increased safety
+
+    template< typename T >
+    inline void checked_delete(T * x)
+    {
+        BOOST_STATIC_ASSERT( sizeof(T) != 0 ); // assert type complete at point
+                                               // of instantiation
+        delete x;
+    }
+
+    template< typename T >
+    inline void checked_array_delete(T  * x)
+    {
+        BOOST_STATIC_ASSERT( sizeof(T) != 0 ); // assert type complete at point
+                                               // of instantiation
+        delete [] x;
+    }
+
+//  next() and prior() template functions  -----------------------------------//
+
+    //  Helper functions for classes like bidirectional iterators not supporting
+    //  operator+ and operator-.
+    //
+    //  Usage:
+    //    const std::list<T>::iterator p = get_some_iterator();
+    //    const std::list<T>::iterator prev = boost::prior(p);
+
+    //  Contributed by Dave Abrahams
+
+    template <class T>
+    inline T next(T x) { return ++x; }
+
+    template <class T>
+    inline T prior(T x) { return --x; }
+
+
+//  class noncopyable  -------------------------------------------------------//
+
+    //  Private copy constructor and copy assignment ensure classes derived from
+    //  class noncopyable cannot be copied.
+
+    //  Contributed by Dave Abrahams
+
+    class noncopyable
+    {
+    protected:
+        noncopyable(){}
+        ~noncopyable(){}
+    private:  // emphasize the following members are private
+        noncopyable( const noncopyable& );
+        const noncopyable& operator=( const noncopyable& );
+    }; // noncopyable
+
+
+} // namespace boost
+
+#endif  // BOOST_UTILITY_HPP
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/boost/boost/utility/base_from_member.hpp	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,59 @@
+//  boost utility/base_from_member.hpp header file  --------------------------//
+
+//  (C) Copyright Daryle Walker 2001.  Permission to copy, use, modify, sell
+//  and distribute this software is granted provided this copyright
+//  notice appears in all copies.  This software is provided "as is" without
+//  express or implied warranty, and with no claim as to its suitability for
+//  any purpose.
+
+//  See http://www.boost.org for most recent version including documentation.
+
+#ifndef BOOST_UTILITY_BASE_FROM_MEMBER_HPP
+#define BOOST_UTILITY_BASE_FROM_MEMBER_HPP
+
+#include <boost/utility_fwd.hpp>  // required for parameter defaults
+
+
+namespace boost
+{
+
+//  Base-from-member class template  -----------------------------------------//
+
+// Helper to initialize a base object so a derived class can use this
+// object in the initialization of another base class.  Used by
+// Dietmar Kuehl from ideas by Ron Klatcho to solve the problem of a
+// base class needing to be initialized by a member.
+
+// Contributed by Daryle Walker
+
+template < typename MemberType, int UniqueID >
+class base_from_member
+{
+protected:
+    MemberType  member;
+
+    explicit  base_from_member()
+        : member()
+        {}
+
+    template< typename T1 >
+    explicit base_from_member( T1 x1 )
+        : member( x1 )
+        {}
+
+    template< typename T1, typename T2 >
+    base_from_member( T1 x1, T2 x2 )
+        : member( x1, x2 )
+        {}
+
+    template< typename T1, typename T2, typename T3 >
+    base_from_member( T1 x1, T2 x2, T3 x3 )
+        : member( x1, x2, x3 ) 
+        {}
+
+};  // boost::base_from_member
+
+}  // namespace boost
+
+
+#endif  // BOOST_UTILITY_BASE_FROM_MEMBER_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/boost/boost/utility_fwd.hpp	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,38 @@
+//  Boost utility_fwd.hpp header file  ---------------------------------------//
+
+//  (C) Copyright boost.org 2001.  Permission to copy, use, modify, sell
+//  and distribute this software is granted provided this copyright
+//  notice appears in all copies.  This software is provided "as is" without
+//  express or implied warranty, and with no claim as to its suitability for
+//  any purpose.
+
+//  See http://www.boost.org for most recent version including documentation.
+
+#ifndef BOOST_UTILITY_FWD_HPP
+#define BOOST_UTILITY_FWD_HPP
+
+
+namespace boost
+{
+
+
+//  From <boost/utility/base_from_member.hpp>  -------------------------------//
+
+template < typename MemberType, int UniqueID = 0 >
+    class base_from_member;
+
+
+//  From <boost/utility.hpp>  ------------------------------------------------//
+
+class noncopyable;
+
+template < class A, class B >
+    class tied;
+
+// Also has a few function templates
+
+
+}  // namespace boost
+
+
+#endif  // BOOST_UTILITY_FWD_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cache/copyright.man	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,10 @@
+Parts copyright Andrew Apted 2000-2001, GNU GPL v2
+.br
+Parts copyright André Majorel 1997-2003, GNU GPL v2
+.br
+Parts copyright Matthew W. Miller 2000, GNU GPL v2
+.br
+Parts written by Raphaël Quinet, public domain
+.br
+Parts written by Brendon Wyber, public domain
+.br
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cache/copyright.txt	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,5 @@
+    Parts copyright Andrew Apted 2000-2001, GNU GPL v2
+    Parts copyright André Majorel 1997-2003, GNU GPL v2
+    Parts copyright Matthew W. Miller 2000, GNU GPL v2
+    Parts written by Raphaël Quinet, public domain
+    Parts written by Brendon Wyber, public domain
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cache/pixlist	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,18 @@
+002f2f.png
+E1.png
+E2.png
+e1.png
+e2.png
+logo.png
+logo_small.png
+mirror0.png
+mirrorh.png
+mirrorv.png
+nook1.png
+nook2.png
+slice1.png
+slice2.png
+vflat.png
+vsprite.png
+vtexture.png
+yadex1.png
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cache/srcdate	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,1 @@
+2003-12-28
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cache/uptodate	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,1 @@
+x
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/configure	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,495 @@
+#!/bin/sh
+#
+#	configure - configure script for Yadex
+#	AYM 2002-09-15
+#
+
+# This file is copyright André Majorel 2002-2003.
+#
+# This program is free software; you can redistribute it and/or modify it under
+# the terms of version 2 of the GNU General Public License as published by the
+# Free Software Foundation.
+#
+# 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.
+
+
+set -e
+
+APPNAME=yadex
+VERSION=`cat VERSION`
+
+CC=
+CXX=
+HAVE_GETTIMEOFDAY=
+HAVE_NANOSLEEP=
+HAVE_SNPRINTF=
+HAVE_USLEEP=
+INTERFACE=x11				# "bgi" or "x11"
+PLATFORM=unix				# "dos" or "unix"
+PREFIX=/usr/local
+
+
+#
+#	check - perform a test
+#
+check () {
+  cdir=/tmp
+  cbasename=${APPNAME}_$$.c
+  cout=${APPNAME}_$$.out
+
+  printf '%s' "$3" >$cdir/$cbasename
+  printf 'checking %s...' "$1"
+  if (cd $cdir && $CC -c $cbasename >$cout 2>&1)
+  then
+    echo " yes"
+    eval "$2=1"
+    return 0
+  else
+    echo " no"
+    sed 's/^/> /' $cdir/$cout
+    eval "$2="
+    return 1
+  fi
+}
+
+
+#
+#	genc - generate config.cc
+#
+genc () {
+  pathname=$BUILDDIR/config.cc
+  echo generating $pathname
+  (
+    set -e
+    echo '// DO NOT EDIT -- generated by ./configure'
+    echo
+    echo '#include "config.h"'
+    echo
+    echo 'extern const char *yadex_etc_path[] ='
+    echo '{'
+    sed 's/\\/\\\\/g; s/"/\\"/g; s/^.*/  "&",/;' $BUILDDIR/config.etc
+    echo '  0'
+    echo '};'
+    echo
+    echo 'extern const char *yadex_share_path[] ='
+    echo '{'
+    sed 's/\\/\\\\/g; s/"/\\"/g; s/^.*/  "&",/;' $BUILDDIR/config.share
+    echo '  0'
+    echo '};'
+    echo
+  ) >$pathname
+}
+
+
+#
+#	genbool - generate a boolean macro definition
+#
+genbool () {
+  name=$1
+  if [ -n "`eval echo \\$HAVE_"$name"`" ]; then
+    echo "#define Y_$name"
+  else
+    echo "//#define Y_$name"
+  fi
+}
+
+
+#
+#	genh - generate config.h
+#
+genh () {
+  pathname=$BUILDDIR/config.h
+  echo generating $pathname
+  (
+    set -e
+    echo '// DO NOT EDIT -- generated by ./configure'
+    echo
+    case "$PLATFORM" in
+      dos)
+	echo '#define Y_DOS'
+	echo '//#define Y_UNIX';;
+      unix)
+	echo '//#define Y_DOS'
+	echo '#define Y_UNIX';;
+      *)
+	echo "configure: bad \$PLATFORM \"$PLATFORM\"" >&2
+	exit 1;;
+    esac
+    case "$INTERFACE" in
+      bgi)
+	echo '#define Y_BGI'
+	echo '//#define Y_X11';;
+      x11)
+	echo '//#define Y_BGI'
+	echo '#define Y_X11';;
+      *)
+	echo "configure: bad \$INTERFACE \"$INTERFACE\"" >&2
+	exit 1;;
+    esac
+    genbool GETTIMEOFDAY
+    genbool NANOSLEEP
+    genbool SNPRINTF
+    genbool USLEEP
+    echo
+    echo 'extern const char *yadex_etc_path[];'
+    echo 'extern const char *yadex_share_path[];'
+    echo
+  ) >$pathname
+}
+
+
+
+#
+#	Parse the command line
+#
+while [ "$#" -ge 1 ]
+do
+  case "$1" in
+    --help)
+      echo "Usage:"
+      echo "  configure --help"
+      echo "  configure [--prefix path] [--cc string] [--cxx string]"
+      exit 0
+      ;;
+
+    --cc)
+      shift
+      if [ "$#" -lt 1 ]
+      then
+	echo "configure: --cc requires an argument" 1>&2
+	exit 1
+      fi
+      CC="$1"
+      ;;
+
+    --cc=*)
+      CC=`expr "x$1" : 'x--cc=\(.*\)'`
+      ;;
+
+    --cxx)
+      shift
+      if [ "$#" -lt 1 ]
+      then
+	echo "configure: --cxx requires an argument" 1>&2
+	exit 1
+      fi
+      CXX="$1"
+      ;;
+
+    --cxx=*)
+      CXX=`expr "x$1" : 'x--cxx=\(.*\)'`
+      ;;
+
+    --prefix)
+      shift
+      if [ "$#" -lt 1 ]
+      then
+	echo "configure: --prefix requires an argument" 1>&2
+	exit 1
+      fi
+      PREFIX="$1"
+      ;;
+
+    --prefix=*)
+      PREFIX=`expr "x$1" : 'x--prefix=\(.*\)'`
+      ;;
+
+    -*)
+      echo "configure: bad argument \"$1\"" 1>&2
+      exit 1
+      ;;
+
+    *)
+      echo "configure: too many arguments" 1>&2
+      exit 1
+  esac
+  shift
+done
+
+#
+#	Sanity checks
+#
+if expr "x$PREFIX" : x/ >/dev/null
+then
+  true
+else
+  echo "configure: --prefix: argument is not an absolute path" 1>&2
+  exit 1
+fi
+
+# Solaris /bin/grep doesn't know about -Fx.
+GREP=/usr/xpg4/bin/grep
+[ -x $GREP ] || GREP=grep
+
+#
+#	Look for a C compiler
+#
+#	We try "gcc" first as commercial Unixen often have a bundled
+#	"cc" command that's useless for our purposes (antiquated KNR
+#	compiler or front-end that just hangs waiting for an answer from
+#	some licence manager).
+#
+printf "looking for a C compiler..."
+if [ -n "$CC" ]
+then
+  printf ' using user-supplied value:'
+else
+  CC=gcc
+  if type $CC >/dev/null 2>&1
+  then
+    :
+  else
+    CC=c89
+    if type $CC >/dev/null 2>&1
+    then
+      :
+    else
+      CC=cc
+      if type $CC >/dev/null 2>&1
+      then
+	:
+      else
+	echo " none"
+	echo "error: none of (gcc, c89, cc) work, is your PATH set right?" 1>&2
+	exit 1
+      fi
+    fi
+  fi
+fi
+echo " $CC"
+
+#
+#	Does the C compiler actually work ?
+#
+cdir=/tmp
+cbasename=${APPNAME}_$$.c
+cout=${APPNAME}_$$.out
+printf "checking whether the C compiler works..."
+echo 'int n;' >$cdir/$cbasename
+if (cd $cdir && $CC -c $cbasename >$cout 2>&1)
+then
+  echo " yes"
+else
+  echo " no"
+  sed 's/^/> /' $cdir/$cout
+  echo "error: looks like the C compiler is not working" 1>&2
+  exit 1
+fi
+
+#
+#	Do we have gettimeofday() ?
+#
+check "for gettimeofday" HAVE_GETTIMEOFDAY '
+#include <sys/time.h>
+#include <time.h>
+int main (int argc, char *argv[])
+{
+  struct timeval tv;
+  struct timezone tz;
+  int n = gettimeofday (&tv, &tz);
+  return n;
+}
+' || true
+
+#
+#	Do we have nanosleep() ?
+#
+check "for nanosleep" HAVE_NANOSLEEP '
+#include <time.h>
+int main (int argc, char *argv[])
+{
+  struct timespec ts;
+  ts.tv_sec = 1;
+  ts.tv_nsec = 1;
+  nanosleep (&ts, &ts);
+  return 0;
+}
+' || true
+
+#
+#	Do we have snprintf() ?
+#
+check "for snprintf" HAVE_SNPRINTF '
+#include <stdio.h>
+int main (int argc, char *argv[])
+{
+  char buf[1];
+  int n = snprintf (buf, sizeof buf, "%d", 42);
+  return n;
+}
+' || true
+
+#
+#	Do we have usleep() ?
+#
+check "for usleep" HAVE_USLEEP '
+#include <unistd.h>
+int main (int argc, char *argv[])
+{
+  unsigned long usec = 1;
+  usleep (usec);
+  return 0;
+}
+' || true
+
+#
+#	Look for a C++ compiler
+#
+#	We try "g++" first, then "c++", then "cxx".
+#
+printf "looking for a C++ compiler..."
+if [ -n "$CXX" ]
+then
+  printf ' using user-supplied value:'
+else
+  CXX=g++
+  if type $CXX >/dev/null 2>&1
+  then
+    :
+  else
+    CXX=c++
+    if type $CXX >/dev/null 2>&1
+    then
+      :
+    else
+      CXX=cxx
+      if type $CXX >/dev/null 2>&1
+      then
+	:
+      else
+	echo " none"
+	echo "error: none of (g++, c++, cxx) work, is your PATH set right?" 1>&2
+	exit 1
+      fi
+    fi
+  fi
+fi
+echo " $CXX"
+
+#
+#	Does the C++ compiler actually work ?
+#
+cdir=/tmp
+cbasename=${APPNAME}_$$.cc
+cout=${APPNAME}_$$.out
+printf "checking whether the C++ compiler works..."
+echo 'int n;' >$cdir/$cbasename
+if (cd $cdir && $CXX -c $cbasename >$cout 2>&1)
+then
+  echo " yes"
+else
+  echo " no"
+  sed 's/^/> /' $cdir/$cout
+  echo "error: looks like the C++ compiler is not working" 1>&2
+  exit 1
+fi
+
+#
+#	Create the directory where the build-specific files go
+#
+SYSTEM_RAW="`uname -n`_`uname -a | cksum`"
+SYSTEM="`echo "$SYSTEM_RAW" | tr -dc '[:alnum:]._-'`"
+BUILDDIR=obj/$SYSTEM
+echo "build directory is $BUILDDIR"
+mkdir -p $BUILDDIR
+
+#
+#	FHS paths
+#
+if expr "$PREFIX" : '//*usr/*$' >/dev/null
+then
+  BINDIR=/usr/bin		# FHS-ly correct is /usr/games
+  ETCDIR=/etc/$APPNAME/%v
+  ETCDIRNV=/etc/$APPNAME
+  MANDIR=/usr/share/man
+  SHAREDIR=/usr/share/games/$APPNAME/%v
+  SHAREDIRNV=/usr/share/games/$APPNAME
+elif expr "$PREFIX" : '//*usr//*local/*$' >/dev/null
+then
+  BINDIR=/usr/local/bin		# FHS-ly correct is /usr/local/games
+  ETCDIR=/etc/$APPNAME/%v
+  ETCDIRNV=/etc/$APPNAME
+  MANDIR=/usr/local/man
+  SHAREDIR=/usr/local/share/games/$APPNAME/%v
+  SHAREDIRNV=/usr/local/share/games/$APPNAME
+elif expr "$PREFIX" : '//*opt/*$' >/dev/null
+then
+  echo '/opt ? Surely you mean /opt/something, Mr. Feynman !' 1>&2
+  exit 1
+elif expr "$PREFIX" : '//*opt//*[^/]' >/dev/null
+then
+  BINDIR=$PREFIX/bin
+  ETCDIR=/etc/opt/`expr "$PREFIX" : '//*opt//*\(.*\)'`
+  ETCDIRNV=
+  MANDIR=$PREFIX/man
+  SHAREDIR=$PREFIX/share
+  SHAREDIRNV=
+else					# Probably /home/joe/*
+  BINDIR=$PREFIX/bin
+  ETCDIR=$PREFIX/etc
+  ETCDIRNV=
+  MANDIR=$PREFIX/man
+  SHAREDIR=$PREFIX/share
+  SHAREDIRNV=
+fi
+
+#
+#	Write Makefile.config
+#
+echo generating $BUILDDIR/Makefile.config
+(
+  echo "# DO NOT EDIT -- generated by ./configure"
+  echo
+  echo "BINDIR            = $BINDIR"
+  echo "CC                = $CC"
+  echo "CXX               = $CXX"
+  echo "ETCDIR            = $ETCDIR" | sed "s/%v/$VERSION/g"
+  echo "ETCDIRNV          = $ETCDIRNV"
+  echo "HAVE_GETTIMEOFDAY = $HAVE_GETTIMEOFDAY"
+  echo "HAVE_NANOSLEEP    = $HAVE_NANOSLEEP"
+  echo "HAVE_SNPRINTF     = $HAVE_SNPRINTF"
+  echo "HAVE_USLEEP       = $HAVE_USLEEP"
+  echo "INTERFACE         = $INTERFACE"
+  echo "MANDIR            = $MANDIR"
+  echo "PLATFORM          = $PLATFORM"
+  echo "SHAREDIR          = $SHAREDIR" | sed "s/%v/$VERSION/g"
+  echo "SHAREDIRNV        = $SHAREDIRNV"
+) >$BUILDDIR/Makefile.config
+
+#
+#	YGD files search path
+#
+echo generating $BUILDDIR/config.share
+$GREP -Fvx '' <<EOF >"$BUILDDIR/config.share"
+.
+~/.$APPNAME/%v
+~/.$APPNAME
+$SHAREDIR
+$SHAREDIRNV
+EOF
+
+#
+#	Config files search path
+#
+echo generating $BUILDDIR/config.etc
+$GREP -Fvx '' <<EOF >"$BUILDDIR/config.etc"
+.
+~/.$APPNAME/%v
+~/.$APPNAME
+$ETCDIR
+$ETCDIRNV
+EOF
+
+#
+#	Write config.h and config.cc
+#
+genc 
+genh
+
+exit 0
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/README	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,2 @@
+To generate the contents of this directory, return to the parent
+directory and type "make doc".
Binary file docsrc/002f2f.png has changed
Binary file docsrc/E1.png has changed
Binary file docsrc/E2.png has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/docsrc/README	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,137 @@
+Yadex $VERSION ($SOURCE_DATE)
+
+WHAT IS YADEX ?
+    Yadex is a Doom level (wad) editor for Unix systems running X,
+    including Linux. It supports Doom, Doom II, Ultimate Doom, Final
+    Doom, Heretic, Doom press release pre beta and also, in a more or
+    less limited way, Hexen, Strife and Doom alpha. It is available
+    under the terms of the GPL.
+
+PREREQUISITES
+    You need :
+    - Some flavour of Unix (known to work with AIX, FreeBSD, HP-UX,
+      Irix, Linux, NetBSD, OpenBSD, OpenUnix, QNX and Solaris),
+    - X11R6 or X11R5 and a display of at least 640x480,
+    - a Doom/Doom II/Heretic/Strife iwad (shareware/demo is OK),
+    - GNU make (vanilla make won't do),
+    - a standard C compiler (ISO 9899:1990),
+    - a standard C++ compiler,
+    - hypot() and either nanosleep() or usleep().
+
+BUILDING AND INSTALLING
+    To install in /usr/local :
+
+                    ./configure
+                    make
+                    su -c 'make install'
+
+    To install somewhere else, for example in ~/yadex :
+
+                    ./configure --prefix ~/yadex
+                    make
+                    make install
+
+    To force the use of a particular C/C++ compiler :
+
+                    ./configure --cc gcc-3.3 --cxx g++-3.3 
+                    make
+                    make install
+
+    Got problems getting Yadex to compile ? See doc/faq.html.
+    Got no problem ? Read the FAQ anyway. See doc/faq.html.
+    
+    Beware, the installation OVERWRITES the following files (assuming
+    you're installing in /usr/local) :
+           /etc/yadex/$VERSION/yadex.cfg
+           /usr/local/bin/yadex
+           /usr/local/bin/yadex-$VERSION
+           /usr/local/man/man6/yadex.6
+           /usr/local/man/man6/yadex-$VERSION.6
+           /usr/local/share/games/yadex/$VERSION/doom.ygd
+           /usr/local/share/games/yadex/$VERSION/doom02.ygd
+           /usr/local/share/games/yadex/$VERSION/doom04.ygd
+           /usr/local/share/games/yadex/$VERSION/doom05.ygd
+           /usr/local/share/games/yadex/$VERSION/doom2.ygd 
+           /usr/local/share/games/yadex/$VERSION/doompr.ygd
+           /usr/local/share/games/yadex/$VERSION/heretic.ygd
+           /usr/local/share/games/yadex/$VERSION/hexen.ygd
+           /usr/local/share/games/yadex/$VERSION/strife.ygd
+           /usr/local/share/games/yadex/$VERSION/strife10.ygd
+
+CONFIGURING AND RUNNING
+    Before you run Yadex, you need to tell it where to find your iwads.
+    Assuming you have installed in /usr/local, open
+    /etc/yadex/$VERSION/yadex.cfg with your favourite text editor and
+    insert the appropriate values for the parameters "iwad1", "iwad2",
+    etc. If you don't want Doom II to be the default iwad, also change
+    the value of the "game" parameter.
+
+    You can now run Yadex by typing :
+    
+			  yadex
+
+    A "yadex:" prompt should show. At that prompt, type this :
+    
+			  e map01
+
+    or this :
+
+			  e e1m1
+
+    Have fun !
+
+DOCUMENTATION
+    There is a man page and quite a lot of documentation, most of it in
+    HTML format. Start at :
+
+                          doc/index.html
+
+    If you're upgrading from a previous version of Yadex, please read
+    carefully CHANGES.
+
+STATUS
+    Yadex is work in progress. It still lacks important features like a
+    better interface, cut-and-paste, undo/redo, support for Boom and
+    many more. I know. They will come faster if you help. The source
+    code is a horrible mess. I'm not proud of it. Be indulgent.
+
+LEGAL
+    1. Yadex
+
+    $COPYRIGHT_TXT
+
+    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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+    2. Atclib
+
+    The Yadex distribution includes a subset of Atclib.
+    
+    Atclib is copyright André Majorel 1995-1999 and distributed under
+    the terms of version 2 of the GNU Library General Public License.
+
+    3. Boost
+
+    The Yadex distribution includes a subset of Boost 1.25.0. Boost
+    1.25.0 is copyright various authors and released under the following
+    terms : Permission to copy, use, modify, sell and distribute this
+    software is granted provided this copyright notice appears in all
+    copies.  This software is provided "as is" without express or
+    implied warranty, and with no claim as to its suitability for any
+    purpose.
+
+CONTACT
+    See doc/contact.html for addresses.
+
+AYM $SELF_DATE
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/docsrc/README.doc	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,2 @@
+To generate the contents of this directory, return to the parent
+directory and type "make doc".
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/docsrc/advanced.html	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,140 @@
+<html>
+<head>
+<title>Yadex advanced uses</title>
+</head>
+<body>
+
+<div align="center">
+<img src="logo_small.png" alt="Fancy logo">
+<br>Yadex $VERSION ($SOURCE_DATE)
+<h1>Advanced user's guide</h1>
+<table><tr><td><td width="50%" align="center">
+Under a silly name, this document discusses some issues that
+only "advanced" users might want to know about. If you're a new
+user, you can probably skip this document for the moment.
+
+<td></td></table>
+</div>
+<br>
+<br>
+<br>
+
+		<h2>Scalability</h2>
+
+			<h3>Level size</h3>
+
+Very large levels, that is levels with large numbers of things,
+vertices, linedefs, sidedefs or sectors, affect both memory
+consumption and responsiveness.
+
+<ul>
+<p><li>In theory, the amount of memory needed by Yadex to hold
+a level open for editing is exactly equal to the cumulated size
+of the <code>THINGS</code>, <code>VERTEXES</code>,
+<code>LINEDEFS</code>, <code>SIDEDEFS</code> and
+<code>SECTORS</code> lumps of said level. In practice, it
+probably will be a little higher because of the overhead in the
+memory allocation system.
+
+<p>In addition, each object in the selection consumes about 8
+bytes.
+
+<p>Finally, during certain operations, Yadex creates bit
+vectors. Fortunately, these consume very little memory, about 1
+bit for each object. If you had a level with 32,767 linedefs,
+creating a bit vector for the linedefs would require about
+4&nbsp;kB, which is not much, especially by comparison with the
+447&nbsp;kB that would be needed to store the linedefs
+themselves.
+
+<p><li>The worst problem that large levels cause is not memory
+but CPU cycles.  Yadex spends a lot of its time browsing through
+the entire level data. For example, if you are in linedefs mode,
+every time you move the pointer, Yadex scans the entire linedefs
+table to see which linedef is under the pointer. As the number
+of objects increases, the responsiveness is bound to decrease.
+
+<p>There are several places in DEU where there were algorithms
+in O(2). For example, when you dragged a vertex, the piece of
+code that checked whether you dragged it on top of another
+vertex made about 1/2 N<sup>2</sup> tests, which is unreasonably
+high past a few hundred vertices. I've tried to replace such
+algorithms by ones in N&times;log(N) but some of them might
+remain.
+
+<p>The drag-and-drop code is awfully slow when dragging a large
+number of objects. I'm still not sure why.
+
+<p>The worst offender by far in terms of CPU cycles is the
+display itself, for obvious reasons. Zooming in will make it
+better since Yadex avoids drawing objects that are off-screen.
+Using a pixmap (as is the default) will make it <em>much</em>
+worse as (at least on my system) drawing to a pixmap is way
+slower than drawing to a window. With a large number of objects
+in sight, the difference can be very noticeable.
+
+</ul>
+
+			<h3>Wad size</h3>
+
+<p>Since the directory of all loaded wads is kept in memory all
+the time, in pathological cases this could cause trouble.
+However, I don't think the problem could arise in practice as
+even the biggest wads have directories no larger than about
+100&nbsp;kB.
+
+<p>Wads with a large number of entries tend to cause delays
+because loading them generates several screenfuls of messages.
+I've made those load-time messages much more compact than they
+used to be but there's still enough left to be annoying with
+certain megawads. And, no, there's no way to suppress them (I
+mean the messages &lt;g&gt;).
+
+<p>If and when in-place saving is ever implemented, there'll be
+something to say about it here.
+
+			<h3>Window size</h3>
+
+In the present implementation, the window is probably the worst
+memory and CPU hog. Unless the <code>-P</code> option is used, a
+pixmap is created for the window. For large window sizes, that
+pixmap can be quite large. For example, for a 1024&times;768
+window on a 16-bit display, it would be about 1.5&nbsp;MB large.
+
+<p>On the CPU side, every times the screen is redrawn completely
+(which happens quite often, particularly when dragging objects),
+the pixmap is filled with black and then blitted back to the
+frame buffer. In the above example, that amounts to reading or
+writing no less than about 4.5 million bytes for <em>every</em>
+refresh. This alone could explain why Yadex becomes so sluggish
+when the window size grows.
+
+<p>I plan to remove the pixmap completely and always display
+directly onto the window, like is done when <code>-P</code> is
+given. That would eliminate the need for the blitting step,
+which would cut two thirds of the load. What's more, I strongly
+suspect that clearing and drawing to a window is significantly
+faster than doing the same with a pixmap (because the X server
+typically can't use the video hardware on pixmaps). The problem
+is doing that in a flicker-free fashion.
+
+		<h2>How Yadex deals with wad files</h2>
+
+<p>Yadex keeps the iwad open for the whole duration of the Yadex
+session. The iwad is closed only when Yadex exits. Pwads are
+kept open as long as they are loaded. A pwad is closed only when
+another pwad with exactly the same resources is loaded or, if it
+contains only a level, when that level is saved.
+
+<p>The wad files are opened with a simple <code>fopen()</code>.
+Yadex make no attempt to control the locking. However, even
+though it would probably be possible for another process to open
+a file while Yadex keeps it open, it would nontheless be a bad
+idea.
+
+<p>For more high-level information on how Yadex treats wad
+files, see <a href="wad_specs.html">there</a>.
+
+</p><hr>AYM $SELF_DATE
+</body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/docsrc/contact.html	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,91 @@
+<html>
+<head>
+<title>Contact information</title>
+</head>
+<body>
+
+<div align="center">
+<img src="logo_small.png" alt="Fancy logo">
+<br>Yadex $VERSION ($SOURCE_DATE)
+<h1>Contact information</h1>
+</div>
+<br>
+<br>
+<br>
+
+		<h2><a name="homepage">Home page</a></h2>
+
+<p>The home page is <a
+href="http://www.teaser.fr/~amajorel/yadex/"
+><code>http://www.teaser.fr/~amajorel/yadex/</code></a>,<br>
+mirrored at <a href="http://www.linuxgames.com/yadex/"
+><code>http://www.linuxgames.com/yadex/</code></a>.
+
+		<h2>Mailing lists</h2>
+
+<dl>
+<dt><a
+name="list_yadex-announce"><code>yadex-announce</code></a>
+
+<dd>Announcements regarding Yadex. This is a very low-volume
+list.
+
+<p>To subscribe to <code>yadex-announce</code>, send a message
+to <a href="mailto:ecartis@freelists.org"
+><code>ecartis@freelists.org</code></a> with
+"<code>subscribe&nbsp;yadex-announce</code>" as the subject.
+
+<p>To unsubscribe from <code>yadex-announce</code>, send a
+message to <a href="mailto:ecartis@freelists.org"
+><code>ecartis@freelists.org</code></a> with
+"<code>unsubscribe&nbsp;yadex-announce</code>" as the subject.
+
+<p>You cannot post to this list.
+
+<dt><a name="list_yadex"><code>yadex</code></a>
+
+<dd>General discussions about Yadex. On-topic subjects include
+questions, bug reports, suggesting and discussing features,
+discussing contributions and development issues. This list is
+supposed to be specialized. It is <em>not</em> intended for
+general Doom editing questions, which are better answered <a
+href="help.html">somewhere else</a>.
+
+<p>To subscribe to <code>yadex</code>, send a message to <a
+href="mailto:ecartis@freelists.org"
+><code>ecartis@freelists.org</code></a> with
+"<code>subscribe&nbsp;yadex</code>" as the subject.
+
+<p>To unsubscribe from <code>yadex</code>, send a message to <a
+href="mailto:ecartis@freelists.org"
+><code>ecartis@freelists.org</code></a> with
+"<code>unsubscribe&nbsp;yadex</code>" as the subject.
+
+<p>To post to <code>yadex</code>, send mail to
+<code>spambait@freelists.org</code> (except that it's
+<code>yadex</code>, not <code>spambait</code>).
+
+<p>When following up to the list, quote only the relevant parts
+of the original message. Your efforts to keep the signal/noise
+ratio high are appreciated.
+
+</dl>
+
+
+		<h2><a name="maintainer">Maintainer</a></h2>
+
+<p>Send all email to <code>spambait@freelists.org</code>,
+<em>not</em> to me.</p>
+
+<p>The current maintainer is André Majorel <a
+href="http://www.teaser.fr/~amajorel/"><code>http://www.teaser.fr/~amajorel/</code></a>.</p>
+
+<p>Send all email to <code>spambait@freelists.org</code>,
+<em>not</em> to me.</p>
+
+(It's really <code>yadex</code>, not <code>spambait</code>).</p>
+
+</p><hr>AYM $SELF_DATE
+
+</body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/docsrc/copyright	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,5 @@
+Apted	Andrew	2000-2001	GPL
+Majorel	André	1997-2003	GPL
+Miller	Matthew W.	2000	GPL
+Quinet	Raphaël	1993-1994	PD
+Wyber	Brendon	1993-1994	PD
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/docsrc/credits.html	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,307 @@
+<html>
+<head>
+<title>Credits</title>
+</head>
+<body>
+
+<div align="center">
+<img src="logo_small.png" alt="Fancy logo">
+<br>Yadex $VERSION ($SOURCE_DATE)
+<h1>Credits</h1> 
+</div>
+<br>
+<br>
+<br>
+
+<em>
+  The email addresses have been anti-spammed. To demangle, reverse,
+  apply rot13 (exchange a and n, b and o, etc), replace the equal sign
+  by a at and replace the plus signs in the domain by dots.
+</em>
+
+		<h2>DEU</h2>
+
+<p>Yadex is derived from DEU 5.21 that was written by Raphaël
+Quinet, Brendon Wyber and others. I am deeply indebted to them
+as, if they had not written DEU 5.21 and, more importantly, had
+not kindly released the source code, Yadex wouldn't exist.
+
+<p>Here are the credits from the DEU 5.21 documentation&nbsp;:
+
+<p><pre>* Everybody at id Software for making such great games!
+
+* Brendon Wyber                   (ma+pn+lehoerganp+pfp=erolj.o)
+     The first version of this program was written by Brendon Wyber.
+     Map display, Things editor.
+
+* Raphaël Quinet                  (ro+pn+tyh+rebvsrgabz=gravhd)
+     Much of this program was written by Raphaël Quinet.
+     New interface (mouse, menus, etc).
+     Ability to edit Vertices, Linedefs, Sidedefs, Sectors, and last
+     but certainly not least an AUTOMATIC NODES BUILDER.
+     Even if I rewrote nearly 90% of the code, this editor still has its
+     strong DEU roots... :-)
+
+* Matt Fell                       (zbp+foorpn=ggraeho.ggnz)
+     Author of the great Unofficial Doom Specs.  Making this program
+     would have been impossible if the Specs didn't exist.
+
+* Steve Bareman                   (hqr+rcbu+gvp+rcbu=anzreno)
+     Rewrote the documentation (this file and DEU.TXT)
+     Author of the DEU tutorial (look in the TUTOR directory).
+     Constant promoter of including source code with the editor.
+     For a good FTP...
+         anonymous @ hope.cit.hope.edu (198.110.98.2)
+        (Registered DOOM patches, DEU, and various doom utils for
+         Registered DOOMers only.)
+
+* Trevor Phillips                 (hn+hqr+avgehp+pp=cvyyvuce)
+     Textures viewer in 256 colors
+     Many, many suggestions and improvements to the DEU code.
+
+* Alistair Brown                  (xh+pn+qebsqneo=ajbeB.D.A)
+* Chris Phillips                  (zbp+ablpynu=cfveup)
+* Colin Reed                      (xh+bp+ghnabten=avybp)
+* Dylan Cuthbert                  (xh+bp+xavyhczbp+kvp=ylq)
+     Lots of infos about the Nodes objects.
+     They fixed the bug(s) in my Nodes builder.
+     Looking for cute Doom add-ons?  Get BSP and ZAMBONY!
+
+* Dewi Morgan                     (xh+pn+qebsqneo=antebM.D)
+     Drop-down menus and menu bar.
+     Rewrote and reorganized part of this file.
+     Numerous improvements and suggestions.
+     Now working on a GIF support for DEU.
+
+* Will Ellett                     (hqr+unh+fp=ggryyrj)
+     Configuration file (DEU.INI) and better command line parsing.
+     Lots of suggestions for DEU.
+
+* Barry Bloom                     (hqr+gah+pba=leeno)
+     Maintainer of the official DEU distribution site for the USA:
+          the best DOOM FTP server: infant2.sphs.indiana.edu
+          (DOOM add-ons and utils, collection of WAD files, ...)
+     Also sent some useful suggestions and bug reports.
+     The first martyr of the DOOM cause: his first ftp site (ocf.unt.edu)
+     has been closed by short-minded academic authorities.  &lt;sob!&gt;
+
+* Sven Neuhaus                    (rq+tavc+lyyvy=arif)
+* Billy Chow                      (xh+pn+qebskb+taverravtar=jbup.lyyvo)
+     The most efficient beta-testers!  They keep on finding bugs that
+     most other people never see...
+
+* Jeremy Blackman                 (zbp+bzvxfr+fjravxfr=nzane)
+* Brian Downing                   (hqr+phvh+nfpa=tavajbqo)
+* Ted Vessenes                    (hqr+azh+zbrt=iqrg)
+* Ed Boling                       (hqr+hzng+ahfzng=0419oqr)
+* Greg Grimsby                    (no more E-mail address &lt;sob!&gt;)
+* Michael Emmons                  (hqr+hvs+kvybf=m0pu87rv)
+* Ryan Budney                     (np+ngeroynh+ugnz+mmnw=hole)
+* Cameron Newham                  (hn+zbp+gravv=znp)
+     Numerous comments, suggestions for improvements, and bug reports.
+     They were amongst the first to have faith in DEU and support it.
+
+* Tom Neff                        (zbp+kvanc=ssrag)
+     Not only a good beta-tester, but also the author of the WIF Specs,
+     a text interchange format for Doom levels, based on the DWD files
+     used internally by id Software.
+
+* Dietrich Hempelmann             (rq+aeboerqnc-vah=engnin)
+     Designed the "DEU 5" logo in DEU.TXT.  Great ascii-art... 
+
+* Jean-Serge Gagnon               (np+njnggbh+1ziqnpn=n8tfw)
+     Helped Steve with the docs and improved the DEU tutorial.
+     If you want to see a good WAD file, get FOREST.WAD...
+
+* Sean Malloy                     (zbp+fgp+ufnep=lbyynz)
+     Updated the docs for the stairs, sent some interesting suggestions
+     and bug reports.  Improved display of the LineDef flags, etc.
+
+* Christian Johannes Sladetsch    (hn+mb+gvze+fp+nenyynl=607429f)
+     Better texture display, XMS support (memory swapping).
+
+* Craig Smith                     (hqr+hzng+fp=fpo)
+     Ideas for improvements in the memory allocation routines.
+
+* Tim Dedischew                   (hqr+qanyxnb+fpn+nyri=pfvqrqsx)
+     Working on a realistic 3D previewer for DEU.
+
+* Tobias Ringström                (rf+ferzynup+xrgq=bgave2q)
+     Added the code to distribute floors and ceiling heights.
+
+* Robert Hodkinson                (xh+pn+qebsqneo=abfavxqbH.J.R)
+     Texture alignment (X offset).
+
+* Per Allanson                    (rf+hvy+nqv+qah=ynerc19p)
+     Ported DEU 5.x to GCC + GO32 (DGJPP).
+
+* Per Kofod                       (zbp+cu+xaq+rvyyb=erc)
+     Added the code to display the pointer coords.  Sent some bug reports
+     and suggestions for improvements.
+
+* Jim Pitts                       (hqr+nanvqav+begfn+nfbzvz=fggvc)
+     Maintainer of the 'infant2' FTP site.  Our salvation when the UNT
+     authorities closed the 'ocf' DOOM-only FTP site.  Thanks, Jim!
+
+* Andy Sherwood                   (zbp+gprevqav=nztvar)
+     Patch for Cirrus Logic cards: use the hardware cursor for the mouse.
+
+* "Dino"                          (xh+pn+znuo+fp=2rf-abgfbecf.f)
+     Found 35 new LineDef types!  New ways to raise or lower floors, etc.
+
+* Hank Leukart                    (hqr+grarres+qanyriryp=146cn)
+     Author of the DOOM FAQ.  Publisher of Matt's Unofficial DOOM Specs.
+     He was (and still is) one of the best promoters of DOOM on the net.
+</pre>
+
+		<h2>Contributors</h2>
+
+<p>As for Yadex per se, the contributors are&nbsp;:
+
+<p><dl>
+  <dt><a href="http://www.netspace.net.au/~ajapted/">Andrew J. Apted</a> (AJA)
+  <dd>Wrote the ygd for Boom and EDGE. Variables <code>digit_zoom_base</code>,
+    <code>digit_zoom_step</code> and <code>blindly_swap_sidedefs</code>. Final
+    Doom testing.
+
+  <br><br><dt>Jean Forget (JF)
+  <dd>Provided the base of the "<code>youngest</code>" perl script.
+
+  <br><br><dt><a href="http://my.ohio.voyager.net/~mattm/">Matthew W. Miller</a>
+    (MWM)
+
+  <dd>Wrote most of <code>strife.ygd</code>.
+
+  <br><br><dt><a href="http://www.teaser.fr/~amajorel/">André Majorel</a> (AYM)
+  <dd>Did the rest ;-).
+
+</dl>
+
+		<h2>Other credits</h2>
+
+<p>Other people who deserve some credit regarding Yade and Yadex
+include, by alphabetical order&nbsp;:
+
+<p><dl>
+  <dt>Joseph Carter <code>&lt;teb+anvorq=qeogutax&gt;</code>
+  <dd>Debian package. Convinced me to support
+    <code>/usr/local/share/man/</code>. Put up with my sick makefiles.
+
+  <br><br><dt>Ben Davies <code>&lt;hn+hqr+han+zubo=7205903q&gt;</code> (BD)
+  <dd>A post by him and another one by Nathan Lucas in r.g.c.d.e. led to the
+    development of the "save image to a file" feature. Gave thorough reports.
+
+  <br><br><dt><a href="http://go.to/conmen/">Max Heijndijk</a>
+  <dd>RPM package.
+
+  <br><br><dt>Joe Koperski <code>&lt;zbp+yvnzgbu=vxfercbxrbw&gt;</code> (JK)
+  <dd>Encouragements.
+
+  <br><br><dt>Oliver Kraus <code>&lt;lrs.e-technik.uni-erlangen.de&gt;</code>
+  <dd>Helped with Solaris port.
+
+  <br><br><dt>Ingo van Lil
+  <dd>Bug reports and suggestions.
+
+  <br><br><dt>Udo Munk <code>&lt;zbp+rierfhczbp=zh&gt;</code> (UM)
+  <dd>Requested scrolling with arrow keys and possibility to disable the
+    autoscrolling. Helped a lot with Final Doom compatibility and porting
+    issues. Wrote <a
+    href="ftp://3darchives.in-span.net/pub/idgames/source/">XDoom</a> and <a
+    href="ftp://3darchives.in-span.net/pub/idgames/source/">Xwadtools</a>.
+
+  <br><br><dt>Kim "Sparky" Parrott <code>&lt;hn+gra+nfvr=zyrx&gt;</code>
+  <dd>Indirect bug report.
+
+  <br><br><dt><a href="http://www.cph.demon.co.uk/">Colin Phipps </a>
+  <dd>FreeBSD testing. Wrote the <a
+    href="http://lxdoom.linuxgames.com/notes.html#bsp">fix</a> for <a
+    href="http://www.teaser.fr/~amajorel/doom/bsp23bug.zip">two bugs</a> in
+    BSP&nbsp;2.3. Wrote <a href="http://lxdoom.linuxgames.com/">LxDoom</a>. Now
+    maintains <a href="http://doombsp.sourceforge.net/">BSP</a>.
+
+  <br><br><dt><a href="http://s91291220.onlinehome.us/">Len Pitre</a>
+  <dd>Helped with Strife support.
+
+  <br><br><dt>Jérôme Raciazek
+  <dd>Let me play with his QNX machine.
+
+  <br><br><dt><a href="http://hjem.get2net.dk/RasII/">"Ras2"</a>
+  <dd>More bug reports than everybody else combined. Provides a mirror of the
+    web page.
+
+  <br><br><dt>Josh R. Ray <code>&lt;gra+ltvqbec=lneufbw&gt;</code> (JRR)
+  <dd>Encouragements.
+
+  <br><br><dt>Vedran Rodic (VR)
+  <dd>Reported segfault on "<code>e e<var>n</var>m<var>m</var></code>" in
+    Doom&nbsp;II mode.
+
+  <br><br><dt>Luc Stepniewski
+  <dd>The first to report the compilation error in <code>bitvec.h</code>.
+
+  <br><br><dt>Jan Van der Veken
+  <code>&lt;ro+grahh+rtnyyvi=arxri.erq.ani.anw&gt;</code> (JVDV)
+  <dd>Requested the "brighten or darken sectors" function, single-key linedef
+    splitting, single-key linedefs of sector splitting and scrolling with arrow
+    keys.
+
+  <br><br><dt>The Wildman
+  <dd>Encouragements.
+
+  <br><br><dt>Jonathan Wilson <code>&lt;zbp+yvnzzbbk=wabfyvj&gt;</code>.
+  <dd>Figured out the picture format for the Doom alpha and press release
+    versions and told us about it on rgcde. Without him, Yadex probably
+    wouldn't support them.
+
+  <br><br><dt>Pierre Baillargeon <code>&lt;gra+gfrhdgen=oc&gt;</code>
+  <dt>Carl Barron <code>&lt;zbp+zbpgra+kv=3abeenop&gt;</code>
+  <dt>David Ferguson <code>&lt;zbp+MAPSvfpON=abfhterFqvinD&gt;</code>
+  <dt>John Potter <code>&lt;hqr+chuy+abpyns=erggbcw&gt;</code>
+  <dt>Atgeirr F. Rasmussen <code>&lt;ba+srgavf=eevrtgn&gt;</code>
+  <dt>Ivan Vecerina <code>&lt;zbp+yvnz=priv&gt;</code>
+  <dd>C++ help.
+
+  <br><br><dt>Benjamin Bayart
+  <dt>Ouafae Kotby
+  <dd><code>diff</code> consulting.
+
+  <br><br><dt>Barry Mead
+  <dd>Reported many errors in <code>heretic.ygd</code>.
+
+</dl></p>
+
+<p>If I'm forgetting you, pardon my mistake and please send me a
+mail so that I can repair the omission. Thank you for your
+feedback&nbsp;!
+
+		<h2>Even more credits</h2>
+
+<p>In no particular order, I would like to thank the
+following folks.
+id Software for making Doom and thinking of the "<code>-file</code>"
+option. And releasing the source code.
+Dave Taylor for porting Doom to Unix against commercial logic.
+The people who created Unix and X
+for giving us one of the best platforms around.
+The thousands who worked on GNU, Linux, *BSD and all the libre
+software for giving me a chance to actually use that platform.
+Colin Reed and Lee Killough for writing BSP,
+releasing its source code and kindly allowing me to include it.
+Olivier Montanuy for DeuTex.
+Udo Munk, Colin Phipps, Karl Robillard and Andre Werthmann for
+the Unix ports of Doom, Heretic and Hexen.
+TeamTNT for Boom.
+The authors of the programs I use and of the FAQs,
+specs and tutorials from which I learned.
+The rgcders for their interesting answers and questions.
+The level designers who have made all the wonderful levels
+and graphics I've been admiring.
+Linuxgames and <code>freelists.org</code> for providing the mailing lists.
+The makers of the internet for connecting us all.
+All the other people who help making this world bearable.
+
+</p><hr>AYM $SELF_DATE
+
+</body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/docsrc/deu_diffs.html	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,216 @@
+<html>
+<head>
+<title>Differences between Yadex and DEU 5.21</title>
+</head>
+<body>
+
+<div align="center">
+<img src="logo_small.png" alt="Fancy logo">
+<br>Yadex $VERSION ($SOURCE_DATE)
+<h1>Differences between Yadex and DEU 5.21</h1>
+<table><tr><td></td><td width="50%" align="center">
+<p>If you're an old DEU user, you might find this useful.
+
+<p><strong>Warning&nbsp;: as it has not been updated since
+1998-02, this document is badly out of date.</strong>
+
+<td></td></table>
+</div>
+<br>
+<br>
+<br>
+
+<p>1. SIGNIFICANT CHANGES
+
+<ul>
+<li> ADDED SUPPORT FOR VERSIONS OF DOOM BEYOND 1.2
+  Added support for levels E4Mn. Added linedef and sector types
+  introduced with Doom v1.666.
+<li> ADDED SUPPORT FOR DOOM II
+  Added support for levels MAPnn. Added new linedef and sector types
+  (see above). Added reading sector and wall textures from doom2.wad.
+  Added definition of Doom II things.
+  You now have to replace main= in the config.file by iwad1= and
+  iwad2= and invoke yadex with either "-g doom" or "-g doom2".
+
+<li> INTEGRATED INFO FROM DOOM SPECS 1.6
+  Corrected linedef types and sector types. Reordered sector types.
+  Added new linedef and sector types (see above).
+
+<li> EDITING IN GENERAL
+  <ul>
+  <li> Highlighting: it does not require as much a precise positionning
+    of the pointer as it did (+/-8 pixels instead of +/-4).
+  <li> Made PU PD END HOME scroll only 1/6 screen at a time (not 1/2)
+  <li> Grid: also highlights multiples of 1024 or 256 or 64. This is
+    useful when you are working with small grid steps (E.G. 8) but
+    still need to align to 64.
+  <li> Grid: you can now have a grid finer than 8 or coarser than 256.
+    So you can now do 4-alignment or even 2-alignment. There are two
+    new parameters (gridmin and gridmax) in the config file to set the
+    low and high bounds (default&nbsp;: 4 and 256).
+  <li> Zoom: added 1 extra magnification step (x8).
+  <li> Zoom: vertices green crosses and linedef arrows are never drawn
+    larger than they would at zoom 1.0. This makes editing of crowded
+    areas easier.
+  <li> Status bar: added the name of the file the level being edited comes
+    from.
+  <li> Made checking after moving a vertex onto a linedef much faster. This
+    should be a relief when connecting sectors together
+  <li> Map: now drawn faster, especially when viewing only a part of it.
+  </ul>
+
+<li> EDITING THINGS
+  <ul>
+  <li> Rotate things with W and X in things mode.
+  <li> The thing type dialog is slightly better.
+  <li> You can now enter type in the range [-32749, 32749].
+  </ul>
+
+<li> EDITING SECTORS
+  <ul>
+  <li> Added raising or lowering of a group of sectors.
+  <li> Added brightening or darkening of a group of sectors.
+  <li> Added display of the headroom (ceiling height - floor height).
+  <li> You can now enter type, tag, floor height and ceiling height in the
+    range [-32749, 32749].
+  </ul>
+
+<li> EDITING LINEDEFS &amp; SIDEDEFS
+  <ul>
+  <li> Added function to remove the 2nd sidedef (make linedef single-sided).
+  <li> Added function to make a nook or a boss.
+  <li> Added function to set length of linedef by moving either vertex.
+  <li> You can now enter type, tag, sidedef x-offset and sidedef y-offset
+    in the range [-32749, 32749].
+  </ul>
+
+<li> GENERAL
+  <ul>
+  <li> The slash is also recognized in file names.
+  <li> You can omit the ".wad" in the names of patch wads files (after
+    -pw, -file, READ).
+  <li> Consumes about 20 kB less memory than DEU 5.21 did.
+  </ul>
+
+<li> CAN BE RUN FROM ANY DIRECTORY
+  <ul>
+  <li> The .bgi driver is searched for in the directory where yadex is
+    installed (i.e. where yadex.exe is), not in the current directory.
+  <li> If the config file (yadex.cfg) is not found in the current directory,
+    it is searched for in the installation directory. On the other hand,
+    if the config file is specified with -config on the command line,
+    default locations are not used.
+  </ul>
+  Deu was difficult to run from another directory that its own. Now you
+  can run it from the directory where the file to edit is, just like you
+  do with, for example, a text editor. That's a bit of improvement,
+  believe me! And you still have the possibility of having a .cfg in the
+  current directory, if you want to have different settings locally.
+  You have several different approaches to making yadex available from
+  anywhere&nbsp;:
+  1. put yadex.exe and the .bgi you need in one of the directories of
+     your PATH
+  2. add the yadex directory to your path.
+  3. make a yadex.bat in one of the directories of your path with the
+     line "@&lt;yadex_directory&gt;\yadex %1 %2 %3 %4 %5 %6 %7 %8 %9"
+  Each solution has pros and cons.
+
+<li> DELETED NODES BUILDER. Nodes are NEVER built and you are not queried
+  whether to do it. In 1994, the nodes builder of DEU 5.21 was a
+  pioneer and we have to thank RQ for having done it. However, in 1997,
+  it is perceived as slow and buggy. Better to use an external nodes
+  builder (I use bsp 2.1).
+
+<li> SYNTAX OF THE "EDIT" AND "CREATE" COMMANDS
+  They now take only one argument. It may be either a complete level
+  name (such as "e1m1" or "map01") or a number. For example, "1"
+  matches "map01", "11" matches both "e1m1 and "map11", etc. If there
+  is not exactly 1 level that matches the argument, a list of levels
+  to choose from is displayed. It contains all levels that matched or
+  all levels if 0 matched.
+
+<li> LETS YOU USE NEW FLOOR/CEILING TEXTURES
+  Understands FF_START/F_END and does the proper additions/replacements
+  ATTENTION, BUG: but an old one: if you have a lump that has the same
+  name as the texture to display...
+
+<li> SCREEN SHOT, SAVING TEXTURE TO FILE
+  When editing, Shift-F1 dumps the current window to a 16-colour GIF
+  file named yadex.gif. Works _only_ when in 256-colour mode.
+  In the image viewer, pressing shift-F1 saves the current image to a
+  file of the same name as the image followed by ".gif". That's the
+  only way I know to extract a texture.
+
+<li> LOG FILE
+  To help you keep track of time spent on a wad, Yadex writes down the
+  number of minutes spent editing in a log file. The name of the log
+  file is the same as the name of the .wad file except it has the
+  extension ".yl". The log file is _not_ created if it does not already
+  exist. Example&nbsp;: if you want to enable logging for /foo/bar.wad,
+  you should first create the file /foo/bar.yl.
+</ul>
+
+
+<p>2. COSMETIC CHANGES
+
+<ul>
+<li> #ifdef'd out the funny message (assuming this is used by wizards)
+  and the "Goodbye..." message
+<li> Do not force anymore the name of pwads to upper case.
+<li> changed "LineDefs and SideDefs" to "LD &amp; SD" to make room in the
+  status bar.
+<li> **Spector -&gt; Spectre, **Sargeant -&gt; Sergeant
+<li> "Misc operations" menus now have "..." where due.
+<li> When drawing the map, negative linedef types and linedef/sector tags
+  are now considered non-zero.
+</ul>
+
+
+<p>3. TECHNICAL CHANGES
+
+<ul>
+<li> Replaced c:\bc4\lib by g:\dt\bcpp.402\lib.
+<li> Replaced d:\bc4\include by g:\dt\bcpp.402\include.
+<li> Removed both "-v" from compiler options.
+<li> Added "-mh" to compiler options.
+<li> Removed "/v" from linker options.
+<li> Removed some private functions from deu.h (SelectLevel).
+<li> Do not demand anymore that an EnMn/MAPnn entry have a length of 0
+  because MAP05 and MAP10 in dyst3 failed that test. Just print a
+  warning.
+<li> Further externalized paths in the makefile...
+<li> Increased overlay granularity (to improve memory consumption).
+<li> In the makefile, put explicit /o+ or /o- options in front of all
+  modules. The following modules were previously unqualified&nbsp;: edit
+  editobj objects things wads aym scrnshot. They now all have /o+.
+<li> Put all modules in alphabetical order in deu.h and in the makefile.
+</ul>
+
+<p>4. BUGS OF DEU 5.21 FIXED
+
+<ul>
+<li> Now you can use wall textures in PWADs without getting "Error
+  reading from file" when trying to display the texture in the
+  texture selector. Deutex users don't need the -deu option anymore.
+<li> The numeric keypad can now be used in menus.
+<li> Fixed 4 display bugs in BuildNewMainWad() and ListMasterDirectory
+  that were not noticeable on a little endian machine.
+<li> Menus work better&nbsp;: static right button state is now ignored (you
+  have to press it) and a left button release is ignored unless the
+  pointer was on an item when it was pressed.
+<li> Texture viewer&nbsp;: fixed minor glitch that showed with BIGDOOR7,
+  SKY1, TEKWALL1, TEKWALL5 and some others.
+</ul>
+
+
+<p>5. NEW BUGS
+
+<ul>
+<li> For Doom II, some wall textures are not displayed correctly.
+  Specifically, instead of SW?BRN1, SW?STARG, SW?STON2 and SW?STONE,
+  SW?BRCOM is displayed. Very strange. I don't know why.
+</ul>
+
+</body>
+</html>
Binary file docsrc/e1.png has changed
Binary file docsrc/e2.png has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/docsrc/editing_docs.html	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,102 @@
+<html>
+<head>
+<title>Doom editing docs and tutorials</title>
+</head>
+<body>
+
+<div align="center">
+<img src="logo_small.png" alt="Fancy logo">
+<br>Yadex $VERSION ($SOURCE_DATE)
+<h1>Doom editing docs and tutorials</h1>
+<table><tr><td></td><td width="50%" align="center">
+Links to places where you can learn more about Doom editing in
+general. Most of this also applies to Heretic, Hexen and Strife.
+
+<td></td></table>
+</div>
+<br>
+<br>
+<br>
+
+
+		<h2>General editing</h2>
+
+<ul>
+<li><a href="ftp://3darchives.in-span.net/pub/idgames/docs/editing/sftechs.txt"
+>Adding sprites and flats into a pwad without merging</a>
+<li><a href="ftp://3darchives.in-span.net/pub/idgames/docs/editing/tutorial.txt"
+>DEU and Doom level construction mini-tutorial</a>
+<li><a href="ftp://3darchives.in-span.net/pub/idgames/docs/editing/dmedit16.zip"
+>Doom editing guide</a>
+<li><a href="ftp://3darchives.in-span.net/pub/idgames/docs/editing/metrics.zip"
+>Doom metrics</a>
+<li><a href="ftp://3darchives.in-span.net/pub/idgames/docs/editing/design12.faq"
+>Frequently asked questions about Doom level design</a>
+<li><a href="http://ourworld.compuserve.com/homepages/tappers/dmstrtd.htm"
+>Getting started with Doom editing</a>
+<li><a href="ftp://3darchives.in-span.net/pub/idgames/docs/editing/textures.zip"
+>Managing textures and the "unpegged" attribute</a>
+<li><a href="ftp://3darchives.in-span.net/pub/idgames/docs/editing/rw2dm.zip"
+>Real world to Doom</a>
+<li><a href="http://cres1.lancs.ac.uk/~esasb1/doom/sew/"
+>Steve's encyclopaedia wadeditorica</a>
+<li><a href="http://www.apci.net/~ron1701/handbook/index.html"
+>The unofficial wad designer's handbook</a>
+<li><a href="ftp://3darchives.in-span.net/pub/idgames/docs/editing/wadrefr.zip"
+>Wad author's Doom reference</a>
+</ul>
+
+		<h2>Unix editing</h2>
+
+<ul>
+<li><a href="http://lxdoom.linuxgames.com/tools.html"
+>Colin Phipps' tools page</a>
+<li><a href="http://www.teaser.fr/~amajorel/doom/unix_doom_editing.html"
+>Unix Doom editing</a>
+</ul>
+
+		<h2>Special effects</h2>
+
+<ul>
+<li><a href="ftp://3darchives.in-span.net/pub/idgames/docs/editing/dtricks1.zip"
+>Doom special fx and wad tricks</a>
+<li><a href="http://www.doomworld.com/tutorials/intro.shtml"
+>The Doomworld editing pages</a>
+<li><a href="ftp://3darchives.in-span.net/pub/idgames/docs/editing/ikspcial.zip"
+>Iikka Keränen's special effects wad</a>
+<li><a href="http://www.cybernet.dk/users/jensh/doom/special/"
+>Jens Hykkelbjerg's Doom special effects page</a>
+</ul>
+
+		<h2>Specs</h2>
+
+<ul>
+<li><a href="ftp://3darchives.in-span.net/pub/idgames/docs/editing/dmspec16.zip"
+>The unofficial Doom specs 1.666, zipped text</a>
+<li><a href="http://doomgate.gamers.org/dhs/helpdocs/dmsp1666.html"
+>The unofficial Doom specs 1.666, browsable text</a>
+<li><a href="http://cres1.lancs.ac.uk/~esasb1/doom/udserrs.txt"
+>Errata for the UDS 1.666</a>
+<li><a href="http://cres1.lancs.ac.uk/~esasb1/doom/uds/"
+>The unofficial hypertext UDS, includes Hexen specs</a>
+</ul>
+
+		<h2>Pages with links to more documents</h2>
+
+<ul>
+<li><a href="http://doomgate.gamers.org/dhs/helpdocs/"
+><code>http://doomgate.gamers.org/dhs/helpdocs/</code></a>
+<li><a href="ftp://3darchives.in-span.net/pub/idgames/docs/editing/"
+><code>ftp://3darchives.in-span.net/pub/idgames/docs/editing/</code></a>
+<li><a href="http://www.cybernet.dk/users/jensh/doom/"
+>Jens Hykkelbjerg's Doom editing page</a> (404)
+<li><a href="http://www.doomworld.com/tutorials/intro.shtml"
+>Doomworld's list of editing tutorials</a>
+<li><a href="http://cres1.lancs.ac.uk/~esasb1/doom/"
+>The wadster's guide</a>
+</ul>
+
+<p><hr>AYM $SELF_DATE
+
+</body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/docsrc/faq.html	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,302 @@
+<html>
+  <head>
+    <title>Yadex FAQ</title>
+  </head>
+  <body>
+
+    <div align="center">
+    <img src="logo_small.png" alt="Fancy logo">
+    <br>Yadex $VERSION ($SOURCE_DATE)
+    <h1>Yadex FAQ</h1>
+    </div>
+    <br>
+    <br>
+    <br>
+
+    <h2>Compilation problems</h2>
+
+    <dl>
+      <dt>
+	<strong>
+	  During configure,
+	  <br><code>error: none of (gcc, c89, cc) work, is your PATH set
+	  right?</code>
+	</strong>
+      <dd>
+	<p>
+	  You need a C compiler to compile Yadex.
+	</p>
+
+	<p>
+	  If you have one but it's not in the path, either fix
+	  <code>$PATH</code> or pass the full pathname to the configure script
+	  with the <code>--cc</code> flag (E.G. "<code>./configure --cc
+	  /opt/sfw/bin/gcc</code>").
+	</p>
+
+	<p>
+	  If it's in the path but it's not called <code>gcc</code> or
+	  <code>c89</code> or <code>cc</code>, pass the name to the configure
+	  script with the <code>--cc</code> flag (E.G. "<code>./configure --cc
+	  icc</code>").
+	</p>
+
+      <dt>
+	<strong>During configure,
+	<br><code>error: none of (g++, c++, cxx) work, is your PATH set right?
+	</code></strong>
+      <dd>
+	<p>
+	  You need a C++ compiler to compile Yadex.
+	</p>
+
+	<p>
+	  If you have one but it's not in the path, either fix
+	  <code>$PATH</code> or pass the full pathname to the configure script
+	  with the <code>--cxx</code> flag (E.G.  "<code>./configure --cxx
+	  /opt/sfw/bin/g++</code>").
+	</p>
+
+	<p>
+	  If it's in the path but it's not called <code>g++</code> or
+	  <code>c++</code> or <code>cxx</code>, pass the name to the configure
+	  script with the <code>--cxx</code> flag (E.G. "<code>./configure
+	  --cxx icc</code>").
+	</p>
+
+      <dt><strong>X11/Xlib.h: No such file or directory</strong>
+
+      <dd>
+	<p>
+	  Are you sure you have the Xlib headers&nbsp;? If not, install them.
+	  If you already have them, then find out where they are and change the
+	  "<code>X11INCLUDEDIR =</code>" line in <code>GNUmakefile</code>
+	  accordingly.
+	</p>
+
+      <dt><strong>The compiler chokes on the Xlib headers</strong>
+
+      <dd>
+	<p>
+	  This happens on Solaris 2.6 with GCC 2.95.2. Oliver Kraus says that
+	  the solution is to add "<code>-fpermissive</code>" to "<code>CXXFLAGS
+	  =</code>" in <code>GNUmakefile</code>.
+	</p>
+
+      <dt>
+	<strong>/usr/X11R6/lib/libX11.so: undefined reference to `recv'
+	<br>/usr/X11R6/lib/libX11.so: undefined reference to `connect'
+	<br>/usr/X11R6/lib/libX11.so: undefined reference to `socket'
+	<br>/usr/X11R6/lib/libX11.so: undefined reference to `setsockopt'
+	<br>/usr/X11R6/lib/libX11.so: undefined reference to `shutdown'
+	<br>/usr/X11R6/lib/libX11.so: undefined reference to `gethostbyname'
+	<br>/usr/X11R6/lib/libX11.so: undefined reference to `getservbyname'
+	<br>/usr/X11R6/lib/libX11.so: undefined reference to `getpeername'
+	<br>/usr/X11R6/lib/libX11.so: undefined reference to `getsockname'
+	</strong>
+
+      <dd>
+	<p>
+	  This happens with QNX 6 and other Unices. Add "<code>-lsocket</code>"
+	  to "<code>LDFLAGS =</code>" in <code>GNUmakefile</code>.
+	</p>
+
+      <dt><strong>Solaris: can't resolve <code>gettimeofday()</code></strong>
+
+      <dd>
+	<p>
+	  In <code>GNUmakefile</code>, add "<code>-lrt</code>" after
+	  "<code>-lX11</code>".
+	</p>
+
+      <dt>
+	<strong>Mac OS X:
+	<br><code>al_adigits.o literal C string section (__TEXT,__cstring) does
+	not end with a '\0'</code></strong>
+
+      <dd>
+	<p>
+	  As far as I can see, the code in Yadex is legal C, and Mac OS X's
+	  <code>ld</code> is incorrect in rejecting it. As a workaround, change
+	  the size of <code>al_adigits[]</code> from 36 to 37 in
+	  <code>al_adigits.c</code> and <code>atclib.h</code>. The real fix is
+	  to complain to <a href="http://www.apple.com/">Apple</a> for selling
+	  you a linker that won't link valid C code.
+	</p>
+
+      <dt><strong>GCC 3.0: Yadex 1.5.1 doesn't compile</strong>
+
+      <dd>
+	<p>
+	  Get Yadex 1.5.2 or later.
+	</p>
+
+      <dt>
+	<strong>GCC 2.96: Yadex 1.5.0 doesn't compile</strong>
+
+      <dd>
+	<p>
+	  Get Yadex 1.5.1 or later.
+	</p>
+
+      <dt>
+        <strong>EGCS&nbsp;1.1.2 / SuSE&nbsp;6.2:
+	<br><code>no matching function for call to `menu_c::menu_c (...)'
+	</code></strong>
+
+      <dd>
+	<p>
+	  Apparently, there is a bug in certain EGCS 1.1.2 installations that
+	  makes them choke on <code>src/editloop.cc</code>. I know no
+	  workaround. I'd suggest that you try to get a fix from your
+	  distributor or use another compiler. EGCS&nbsp;1.0.3, EGCS&nbsp;1.1.1
+	  and GCC&nbsp;2.95.2 are known to work. 
+	</p>
+
+      <dt><strong>GCC 2.7: lots of compilation errors</strong>
+
+      <dd>
+	<p>
+	  GCC 2.7 is a very old compiler, it does not implement the current C++
+	  standard and I don't support it. If you must, try applying
+	  <code>patch/gcc-2.7.diff</code> that's included in the archive but
+	  don't complain to me if it doesn't work.
+	</p>
+
+
+      <dt>
+        <strong>GCC:
+	<br><code>warning: comparison between signed and unsigned</code>
+	</strong>
+
+      <dd>
+        <p>
+	  GCC is over-sensitive to signedness mismatches. Don't worry, that
+	  won't prevent Yadex from working.
+	</p>
+
+      <dt>
+        <strong>GCC: In <code>sanity.cc</code>,
+	<br><code>warning: decimal integer constant is so large that it is
+	unsigned</code></strong>
+
+      <dd>
+        <p>
+	  Weird as it may sound, the standard says that the lowest value that a
+	  signed long can hold is -(2^31). GCC sticks to the party line, never
+	  mind that you're on a platform like i386 where <code>LONG_MIN</code>
+	  is -(2^31)&nbsp;-&nbsp;1.
+	</p>
+
+	<p>
+	  You can ignore this warning.
+	</p>
+      
+      <dt>
+	<strong>GCC: In <code>sanity.cc</code>,
+	<br><code>warning: this decimal constant is unsigned only in ISO
+	C90</code></strong>
+
+      <dd>
+        <p>
+	  This is a new avatar (as of GCC 3.3) of the previous warning. Ignore
+	  it.
+	</p>
+
+      <dt><strong>Yadex 1.3.1 doesn't compile</strong>
+
+      <dd>
+        <p>
+	  There's a thinko in the makefile. It's fixed in version 1.3.2.
+	</p>
+
+      <dt><strong>Yadex 1.1.0 doesn't compile</strong>
+
+      <dd>
+        <p>
+	  In <code>src/infobar.cc</code>, lines 48 and 49, replace
+	</p>
+
+<pre>  const char infobar_c::FILE_NAME_UNSET[1];  // A special pointer value 
+  const char infobar_c::LEVEL_NAME_UNSET[1];  // A special pointer value</pre>
+
+	<p>
+	  by
+	</p>
+
+<pre>  const char infobar_c::FILE_NAME_UNSET[1] = { ' ' };
+  const char infobar_c::LEVEL_NAME_UNSET[1] = { ' ' };</pre>
+
+      <dt><strong>Yadex 1.0.1 doesn't compile</strong>
+
+      <dd>
+        <p>
+	  In <code>src/vector.h</code>, delete line 44 ("<code>return
+	  this;</code>") and compile again.
+	</p>
+    </dl>
+
+	    <h2>Misc.</h2>
+
+    <dl>
+      <dt><strong>I don't have an iwad</strong>
+
+      <dd>
+        <p>
+	  You can download certain iwads for free&nbsp;;
+	</p>
+
+	<ul>
+	  <li><a href="ftp://ftp.idsoftware.com/idstuff/doom/doom-1.8.wad.gz"
+	  >Doom 1.8 shareware iwad</a>
+	  <li><a href="ftp://ftp.idsoftware.com/idstuff/heretic/htic_v12.zip"
+	  >Heretic shareware version</a>
+	  <li><a href="ftp://ftp.idsoftware.com/idstuff/hexen/hexndemo.zip"
+	  >Hexen demo</a>
+	  <li><a href="http://www.rogue-ent.com/sfiles.html"
+	  >Strife demo</a>
+	</ul>
+
+      <dt><strong>What about a 3D preview&nbsp;?</strong>
+
+      <dd>
+        <p>
+	  Andrew Apted has written an amazing <a
+	  href="http://glbsp.sourceforge.net/files/RenderDiff.gz">patch</a>
+	  that does exactly that.
+	</p>
+
+      <dt><strong>Yadex is slow, particularly when dragging objects</strong>
+
+      <dd>
+        <p>
+	  Yes. I plan to replace the current implementation (pixmap) by drawing
+	  directly to the window. The difficulty lies in making that without
+	  generating a lot of flicker. In the meantime, try the <code>-P</code>
+	  option.
+	</p>
+
+      <dt><strong>How many people use Yadex&nbsp;?</strong>
+
+      <dd>
+        <p>
+	  I don't know for sure. Each new release gets a few hundred downloads.
+	</p>
+
+      <dt><strong>Why didn't you use &lt;insert speaker's favourite
+	toolkit&gt;&nbsp;?</strong>
+
+      <dd>
+        <p>
+	  I used plain Xlib and not a toolkit for several reasons. Firstly, I
+	  wanted to learn Xlib. Secondly, I reckoned it would be easier to
+	  translate the existing BGI calls to Xlib than to some higher level
+	  toolkit. Thirdly, I feared that depending on a toolkit would hurt
+	  portability.
+	</p>
+    </dl>
+
+    <hr>AYM $SELF_DATE
+
+  </body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/docsrc/feedback.html	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,46 @@
+<html>
+<head>
+<title>User feedback</title>
+</head>
+<body>
+
+<div align="center">
+<img src="logo_small.png" alt="Fancy logo">
+<br>Yadex $VERSION ($SOURCE_DATE)
+<h1>User feedback</h1>
+</div>
+<br>
+<br>
+<br>
+
+		<h2>Reporting success</h2>
+
+<p>Reports of success are welcome and appreciated. Send mail to
+the current <a href="contact.html#maintainer">maintainer</a>.
+
+		<h2>Reporting bugs</h2>
+
+<p>See <a href="reporting.html">there</a>.
+
+		<h2>Criticism and suggestions</h2>
+
+<p>Qualified and specific criticism is useful. Some of the best
+features in Yadex come from user suggestions.  Send mail to the
+<a href="contact.html#list_yadex"><code>yadex</code></a> mailing
+list.
+
+<p>Yes, suggestions to switch to toolkit <var>x</var> have
+<em>already</em> been offered for most values of <var>x</var>.
+There even is a <a href="faq.html">FAQ</a> item.
+
+<p>For a list of known issues and solutions that have been
+considered, see <a href="TODO"><code>TODO</code></a>.
+
+		<h2>Contributions</h2>
+
+<p>See the <a href="hackers_guide.html">hacker's guide</a>.
+
+</p><hr>AYM $SELF_DATE
+
+</body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/docsrc/getting_started.html	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,358 @@
+<html>
+<head>
+<title>Getting started with Yadex</title>
+</head>
+<body>
+
+<div align="center">
+<img src="logo_small.png" alt="Fancy logo">
+<br>Yadex $VERSION ($SOURCE_DATE)
+<h1>Getting started with Yadex</h1>
+<table><tr><td></td><td width="50%" align="center">
+If you're new to Yadex, this is what you want to read first.
+<td></td></table>
+</div>
+<br>
+<br>
+<br>
+
+	<h2><a name="introduction">
+	1. Introduction</a></h2>
+
+		<h3>Yadex in one paragraph</h3>
+
+<p>Yadex is a Doom level (wad) editor for Unix systems running
+X, including Linux. It supports Doom, Doom II, Ultimate Doom,
+Final Doom, Heretic and also, in a more or less limited way,
+Hexen and Strife. It is available under the terms of the GPL.
+
+		<h3><a name="prerequisites">What do I need ?</a></h3>
+
+<p>To compile, install and run this release of Yadex, you need
+<ul>
+<li>a POSIX-compatible environment (such as Unix),
+<li>an ISO-compliant C/C++ compiler
+<li>GNU make (it won't work with other flavours of make),
+<li>an HTML viewer to read the doc,
+<li>a Doom/Doom II/Heretic iwad.
+<li>X11R6 or X11R5.
+</ul>
+
+<p>More specifically, Yadex expects that
+<ul>
+<li>the routines in <code>ctype.h</code> accept the range
+	<code>CHAR_MIN</code> through <code>UCHAR_MAX</code>,
+<li>the C library has the <code>hypot()</code> function,
+<li>either the <code>nanosleep()</code> or the
+	<code>usleep()</code> system call is supported.
+</ul>
+
+		<h4>Iwad</h4>
+
+<p>A shareware Doom/Heretic/Strife iwad is okay but you need a
+registered iwad if you want to be able to save your changes.
+
+		<h4>Directories</h4>
+
+<p>Yadex conforms to the <a href="http://www.pathname.com/fhs/">
+FHS (filesystem hierarchy standard)</a>.
+The installation procedure will try to copy files in the following
+directories, creating the directories if they don't exist ;
+<ul>
+<li><code>/etc/yadex/$VERSION</code>
+<li><code>/usr/local/bin</code>
+<li><code>/usr/local/share/games/yadex/$VERSION</code>
+</ul>
+<p>So make sure you have the necessary rights before installing
+(or install in a different location).
+
+		<h4>Display</h4>
+
+<p>Yadex uses about 270 different colours. In most cases, on
+PseudoColor displays, there aren't that many free colour cells.
+So, if it detects a PseudoColor display, Yadex uses a private
+colormap so as to get as many free colour cells as possible.
+The inconvenient of this method is that, when you're in the
+Yadex window, all other windows are displayed with wrong colours
+and vice-versa.
+
+<p>What's more, as PseudoColor displays typically have 256
+colours (at least on PC), which is less than the number of
+colours needed, Yadex might have to assign the same physical
+colour to different logical colours. If it happens, it will try
+to render the colours of the game accurately at the expense of
+the application colours.
+
+<p>Monochrome displays might work but they have not been tested.
+
+<p>Executive summary: if you can, use a TrueColor or DirectColor
+display and a depth of more than 8 bits per pixel (E.G. by
+launching X with "<code>startx -- -bpp 16</code>").
+
+<p>A 640x480 screen is okay though, of course, a larger display
+is better.
+
+	<h3><a name="compiling">Compiling and installing Yadex</a></h3>
+
+See <a href="README"><code>README</code></a>.
+
+<p>Don't forget to tell Yadex where your iwads are by changing
+the lines "<code>iwad1&nbsp;=</code>",
+"<code>iwad2&nbsp;=</code>" etc. in
+<code>~/.yadex/yadex.cfg</code> or
+<code>/etc/yadex/$VERSION/yadex.cfg</code> (the actual location
+might be different if you compiled with another prefix than the
+default). If there is an iwad you don't have, you can just
+comment out the corresponding line.
+
+	<h2><a name="quick_start">
+	2. Quick start</a></h2>
+
+		<h3>I know nothing about Doom editing</h3>
+
+<p>This section is meant to be a quick introduction to using
+Yadex. I assume you already know the basics of Doom editing,
+i.e. what vertices, linedefs, sidedefs, things and sectors are
+and how they work together. If you don't, it would be good idea
+to go get a Doom editing tutorial (see the <a
+href="editing_docs.html">list</a>). If at first it seems
+confusing, persevere. It worked for me anyway ;-).
+
+		<h3><a name="q_running">
+		How do I run Yadex ?</a></h3>
+
+<p>You must have successfully compiled, installed and configured Yadex.
+If you haven't, see <a href="users_guide.html#compiling">there</a>.
+
+<p>For the sake of discussion, we'll assume you want to edit MAP01
+of Doom II. From the shell, type&nbsp;:
+<p>
+<code>$ </code><kbd>yadex -g doom2</kbd>
+<p>
+(of course, you don't have to type the "<code>$</code>" !)<br>
+You should see a couple of messages
+and then the Yadex prompt, which looks like this&nbsp;:
+<p>
+<code>yadex: </code>
+<p>
+At this prompt, type&nbsp;:
+<p>
+<code>yadex: </code><kbd>e map01</kbd>
+<p>
+(once again, don't type the "<code>yadex:</code>" string&nbsp;!)<br>
+The editor window opens.
+
+		<h3>Moving around in the edit window</h3>
+
+<p>There you are. What you should see now is a window with the map
+of the level you wanted to edit.
+
+<br><br><table>
+<tr><td><img src="yadex1.png" alt="Screenshot of fresh Yadex window" WIDTH=600 HEIGHT=450>
+<tr><td align="right"><i>Fresh Yadex window</i>
+</table>
+
+<p>At the top of the window, there is the menu bar.
+I assume you know what a menu bar is.
+At the bottom of the window, there is the info bar.
+It displays some information about your current status&nbsp;:
+the name of the level you're editing,
+whether it has changed since last saved,
+in which editing mode you are,
+etc.
+
+<p>Try to move the pointer around. Note that the info bar
+shows the position of the pointer in map coordinates.
+
+<p>If you press [<kbd>Left</kbd>], [<kbd>Right</kbd>],
+[<kbd>Up</kbd>], [<kbd>Down</kbd>], [<kbd>Home</kbd>],
+[<kbd>End</kbd>], [<kbd>Page-up</kbd>] or
+[<kbd>Page-down</kbd>], the map scrolls.
+
+<p>You can also zoom in and out by pressing [<kbd>+</kbd>] and
+[<kbd>-</kbd>].
+
+		<h3>Highlighting, selecting, dragging, changing properties</h3>
+
+<p>As you are now in "things" mode (as you can see on the info
+bar), every time you pass over a thing, it is highlighted and a
+window pops up in the bottom left corner of the window that
+shows the properties of that thing.
+
+<p>What if you want to change the properties of a thing ?
+Double-click on it or highlight it and press
+[<kbd>Return</kbd>]. A menu pops up in the top left corner of
+the window. Select the property you want to change and yet
+another window pops up. Enter the new value of the property and
+that's it.
+
+<p> You can drag things around ; click on the thing and, without
+releasing the button, move the pointer to where you want to move
+it to and then release the button. If you want to move a group
+of things, select them all, and drag one of them. All selected
+things follow.
+
+<p>To select several things, you can either hold
+[<kbd>Ctrl</kbd>] down and click on each of them in turn or
+select them all at once with a selection box. To do that, click
+on an empty spot and, without releasing the button, move the
+pointer to where you want the other corner of the box to be.
+Then release the button&nbsp;; all the things within the box are
+selected.
+
+<p>Note that when you start a selection box, everything else is
+unselected. If you don't want that to happen, hold
+[<kbd>Ctrl</kbd>] down while you draw the box. Thus you can
+<em>add</em> the contents of the new box to the selection.
+
+		<h3>Deleting and creating</h3>
+
+<p>You can delete things by pressing [<kbd>Del</kbd>]. It will
+delete all selected things or, if there is no selection, the
+highlighted thing.
+
+<p> You can also create a new thing under the pointer by
+pressing [<kbd>Ins</kbd>]. If, at the moment you press
+[<kbd>Ins</kbd>], there is a thing highlighted, the new thing
+will be created with the same properties as its "model". Else,
+it will have the default properties as defined in the
+Preferences.
+
+		<h3>Modes</h3>
+
+<p>So far we've only edited things. Now how do we edit other
+objects ? As I've said before, you're in "things" mode. If you
+press [<kbd>Tab</kbd>], you will switch to the next mode, that
+is the vertices mode. Press [<kbd>Tab</kbd>] again and you are
+in linedefs-and-sidedefs mode. Press [<kbd>Tab</kbd>] again and
+you are in sectors mode. Press [<kbd>Tab</kbd>] again and you
+are back in things mode. You can also use
+[<kbd>Shift-Tab</kbd>] to cycle backwards through the modes and
+[<kbd>t</kbd>], [<kbd>v</kbd>], [<kbd>l</kbd>] and
+[<kbd>s</kbd>] to go directly to a particular mode. 
+
+<p> The other modes work like the things mode except that you
+operate on different types of objects.
+
+		<h3>Zooming and the grid</h3>
+
+<p>Use [<kbd>g</kbd>] and [<kbd>G</kbd>] to change the grid
+step.
+<br> Use [<kbd>y</kbd>] if you want to be able to place
+objects "off" the grid.
+
+		<h3>Creating complex objects</h3>
+
+<p>Click on the "Objects" item on the menu bar
+or press [<kbd>F9</kbd>] and look at the menu that pops up.
+<br>
+You can also create a sector from a path of linedefs
+by selecting those linedefs and pressing [<kbd>Ins</kbd>].
+<br>
+You can create a linedef between two vertices
+by selecting those vertices and pressing [<kbd>Ins</kbd>].
+
+		<h3>Advanced functions</h3>
+
+<p>Click on the "Misc" item on the menu bar
+or press [<kbd>F8</kbd>] in different modes
+and look at the menu that pops up.
+
+		<h3>Checks</h3>
+
+<p>Click on the "Checks" item on the menu bar
+or press [<kbd>F10</kbd>] and look at the menu that pops up.
+
+		<h3>Saving and exiting</h3>
+
+<p>If you still haven't, please make some modifications to the
+level. For example change some textures and light levels and
+add, say, a dozen of cyberdemons in the courtyard.
+
+<p>I want you to save the modified level to a pwad named
+<code>mywad.wad</code> so that you can test it with Doom. To do
+that, press [<kbd>F2</kbd>]. Don't worry, it will not overwrite
+your iwad. Individual levels are always saved to a pwad. You
+are prompted for a file name. Enter <code>mywad.wad</code>.
+
+<p> Before when go on, here a few things worth mentioning&nbsp;:
+
+<p>
+<ul>
+<li>
+If you press [<kbd>Esc</kbd>], you quit without saving.
+If you have unsaved changes, you are asked to confirm.
+<br>
+If you press [<kbd>q</kbd>], you save and quit.
+<br>
+If you press [<kbd>F2</kbd>], you save.
+<br>
+If you press [<kbd>F3</kbd>], like [<kbd>F2</kbd>] but
+you can save under a different level name (E.G. MAP02).
+
+<p><li>Whenever you are queried for a file name, remember that
+the <code>.wad</code> extension is <em>not</em> automatically
+appended. In addition, if you used to be a DOS/Windows user,
+remember that Unix treats file names in a case-sensitive fashion
+so you'd better think twice before using names like FOO.WAD.
+
+<p><li>When a <code>.wad</code> file is changed, a backup is made
+in the same directory and with the same name but with the
+extension <code>.bak</code>.
+
+<p><li>I said above that iwads are not overwritten. The same is
+not true of pwads. If you edit a level that comes from a pwad,
+it will be saved to the same pwad file, unless you specify a
+different file name.
+
+<p><li><strong>GOTCHA: when you save to a pwad, everything that
+used to be in that pwad is lost !</strong> For example, if you
+load a pwad that contains MAP01 and MAP02, edit MAP01 and save
+MAP01 to the same pwad file, the level MAP02 it used to contain
+is <em>lost</em>&nbsp;! It's unfortunate but not very easy to
+fix.
+
+</ul>
+
+<p>Now press [<kbd>Esc</kbd>]. The editing window closes and
+you are returned to the Yadex prompt. From there, use the
+"<code>e</code>" or "<code>c</code>" commands to edit another
+level or use the "<code>q</code>" command to really quit Yadex.
+
+		<h3>Testing your level</h3>
+
+<p><strong>GOTCHA: Before you test your level, you MUST run it
+through a nodes builder.</strong> If you don't, you'll get
+strange results or you'll crash the game.
+
+<p>There are several nodes builders around. One of the best is
+BSP, which you can download from <a
+href="http://doombsp.sourceforge.net/"><code
+>http://doombsp.sourceforge.net/</code></a>. To build the nodes
+on your level with BSP and then test it with Doom, type
+something along the lines of&nbsp;:
+
+<p><pre>
+$ bsp -o final.wad mywad.wad
+$ doom -file final.wad
+</pre>
+
+		<h3>Fixing your level</h3>
+
+<p>You've tested your level and you've found that some things
+need to be fixed. What do you do ? Well, go back to <a
+href="#q_running"> How do I run Yadex</a> except that, this
+time, you need to tell Yadex to load your pwad. You do that by
+running Yadex with the name of your pwad as argument (you can
+ommit the <code>.wad</code> extension). E.G.&nbsp;:
+
+<p>
+<code>$ yadex -g doom2 mywad</code>
+<p>
+That's it&nbsp;! You've been through an entire
+edit-build-test-edit cycle. Doubtlessly the first of thousands
+:-).
+
+<p><hr>AYM $SELF_DATE
+</body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/docsrc/hackers_guide.html	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,1216 @@
+<html>
+<head>
+<title>Yadex hacker's guide</title>
+<meta http-equiv="Content-Style-Type" content="text/css">
+<style type="text/css">
+  DT {
+    margin-bottom:       1em;
+    margin-top:          1em;
+    display:             list-item;
+    list-style-image:    none;
+    list-style-position: inside;
+    list-style-type:     disc;
+  }
+  DD {
+    margin-bottom: 1em;
+    margin-top:    1em
+  }
+</style>
+</head>
+<body>
+
+<div align="center">
+<img src="logo_small.png" alt="Fancy logo">
+<br>Yadex $VERSION ($SOURCE_DATE)
+<h1>Hacker's guide</h1>
+</div>
+<br>
+<br>
+<br>
+
+		<h2>Read this first</h2>
+
+Before you start hacking&mdash;no, before you even
+<em>think</em> about hacking&mdash;Yadex, you should do
+this&nbsp;:
+
+<dl>
+  <dt>Read the <a href="TODO"><code>TODO</code></a> file
+
+  <dd>
+    Many possible improvements and fixes have been identified
+    and sometimes a particular approach has already been decided
+    on and written down in <code>TODO</code>. Yes it's tedious
+    reading. But if you skip it, you run the risk of seeing your
+    work go to waste because it's in conflict with an earlier
+    plan.
+
+  <dt>Read the <a href="hackers_guide.html">hacker's guide</a>
+
+  <dd>
+    Patches that don't <em>at the minimum</em> abide by the
+    coding standards and other guidelines in this document are
+    not very likely to be accepted.
+
+  <dt>Subscribe to the <a
+    href="contact.html#list_yadex"><code>yadex</code> list</a>
+
+  <dd>
+    The mailing list is the way by which users and developers
+    communicate. Subscribe to the list and do all communication
+    through the list. It allows developers to coordinate and to
+    benefit from the feedback of all other developers and users.
+    
+    <p>
+      For whatever reason, some contributors seem to think they
+      don't need to subscribe to the list. But the need for
+      coordination remains. Each contributor needs a
+      communication channel with the rest of the project. If
+      it's not the mailing list, it'll probably be the
+      maintainer (me) and I don't want to have to play the role
+      of a mailing list digest server.
+    </p>
+
+    <p>
+      Having a single many-to-many communication channel is
+      better than having many one-to-one channels because you
+      don't have to repeat the same thing <var>n</var> times to
+      <var>n</var> people.
+    </p>
+
+    <p>
+      The mailing list is archived and the archives are publicly
+      accessible by anyone at any time. Private mail isn't.
+    </p>
+
+  <dt>Post on the list about your plans
+  
+  <dd>
+    The job you want to do might be already underway, or might
+    be conflicting with something else.
+
+</dl>
+
+		<h2>Blah</h2>
+
+			<h3>Foreword</h3>
+
+This documents is aimed at people
+who want to hack Yadex.
+It is very incomplete,
+partly due to lack of time,
+partly because as some subsystems are going to be rewritten,
+I'd rather not spend too much time documenting them.
+But if you're interested in a particular area
+of Yadex's bowels that does not appear here,
+don't hesitate to let me know.
+<p>
+I apologize for the poor quality of Yadex's code
+but it seemed to me it was better to release
+something imperfect now
+than something clean two years from now.
+If you want to improve it, be my guest.
+
+			<h3>Introduction</h3>
+
+Yadex is written in a mixture of C and C++.
+The Unix version interfaces with X through Xlib directly&nbsp;;
+it uses no toolkit.
+The DOS version uses BGI (Borland Graphics Interface),
+a rather low-level API to set the video mode, draw lines, text, etc.
+
+			<h3>Original platform</h3>
+
+The Unix version has been developped with
+GCC 2.7.2, EGCS 1.0.3, EGCS 1.1.1, libc5, glibc2 and XFree 3.3
+on a PC K6/200 with Linux 2.0.29, 2.0.30 and 2.0.34.
+<p>
+The DOS version has been developped with
+Borland C++ 4.0
+on a PC 486 DX4/75 with MS-DOS 6.22.
+<p>
+Yadex should be compilable on all reasonable
+Unix-and-X11 platforms provided that 
+<ul>
+<li>you have GNU make,
+<li>you have a C compiler and a C++ compiler,
+<li>$c short is 16-bit long,
+<li>$c long is 32-bit long.
+</ul>
+To compile on platforms where $c short
+or $c long don't have the needed size,
+just change the definitions of $c u16,
+$c i16, $c u32 and $c i32
+in $c yadex.h.
+
+			<h3>Historic background</h3>
+
+Yadex descends from DEU 5.21.
+<p>
+DEU 5.21 was written by Raphaël Quinet, Brendon Wyber and others
+and released on 1994-05-21.
+As you probably already know,
+DEU was a real-mode DOS program,
+in C, compiled with Borland C++ 4.0 (I think)
+and using BGI for its output.
+<p>
+In the mists of time (that is probably 1996),
+I began to hack DEU for my own use.
+In 1997, other people began to use my hack
+and I gave it a name : "Yade"
+(which meant Yet Another Doom Editor).
+It was still a real-mode DOS program.
+<p>
+In june 1998, tired of rebooting to DOS
+every time I wanted to do some Doom level editing,
+I started porting Yade to Linux.
+As there already was a Unix program called "Yade"
+(Yet Another Diagram Editor),
+I changed the name of my baby to "Yadex".
+At the same time, I began to use C++ in places
+so that's why Yadex is such an ugly mixture of languages.
+
+		<h2>Development cycle</h2>
+
+			<h3>Compiling, installing, testing</h3>
+
+<p>OK. So I want to hack Yadex&nbsp;; what do I do now&nbsp;?
+The obvious development cycle is
+
+<ol>
+  <li>modify the files in <code>src/</code>,
+  <li>type <code>make</code>,
+  <li>type <code>su -c 'make install'</code>,
+  <li>run Yadex and test.
+</ol>
+
+<p>However, there are a few things to know that can make you
+more efficient.
+
+<p>To compile with debugging information, you don't have to
+modifiy the makefile&nbsp;; just use the appropriate target
+(<code>dyadex</code>). The resulting executable is put in
+<code>dobj/0/</code> instead of <code>obj/0/</code>.
+
+<p>You don't have to install to test&nbsp;: you can test in
+place with the special targets <code>test</code> and
+<code>dtest</code> (<code>test</code> is for the regular
+executable, <code>dtest</code> is for the debugging executable
+and is my favourite target by far). When testing through make,
+you can't pass arguments to Yadex directly&nbsp;: you have to
+pass them through the <code>A</code> macro. For example&nbsp;:
+
+<pre>  $ <b>make dtest A='-g heretic foo.wad'</b></pre>
+ 
+<p>You can also run your hack through the debugger with the
+<code>dg</code> (GDB) and <code>dd</code> (DDD) targets. With
+those targets, you can't use the <code>A=</code>
+convention&nbsp;: you have to type "<code>set args blah blah
+blah</code>" at the debugger prompt.
+
+<pre>  $ <b>make dg</b>
+  (gdb) <b>set args -g heretic foo.wad</b>
+  (gdb) <b>run</b></pre>
+
+<p>Even if you want to install your hack, you may want to keep
+the original Yadex around, for reference or for a good laugh.
+To do that, edit the <code>VERSION</code> file before compiling
+your hack. If your hack bears a different version number, it
+will not overwrite the original version. You don't have to
+change the version number much&nbsp;: you can just change
+"<code>3.8.0</code>" into "<code>3.8.0a</code>" or
+"<code>3.8.0.0</code>" for example.
+
+<p>
+
+		<h2>The programming environment</h2>
+
+			<h3>Memory allocation</h3>
+
+You're not supposed to use $c malloc() and $c free() but $c
+GetMemory(), $c FreeMemory(), $c GetFarMemory() and $c
+FreeFarMemory() instead. Why ?
+
+<p>$c GetMemory() and friends manage more things for you.  They
+include an anti-fragmentation system, they try to swap things
+out when memory is tight (this is an only an issue for the
+16-bit DOS version) and if they fail, they call $c fatal_error()
+so you don't need to check their return value.
+
+<p>The reason for $c GetFarMemory() is that, for the 16-bit DOS
+version, it can allocate more than 64 kB ($c GetMemory()
+cannot). I must say that I don't use $c GetFarMemory() a lot
+myself because I don't like the idea of having to use two
+different memory allocation routines depending on the size I
+expect to allocate. I modified $c GetMemory() so that it accepts
+an <code>unsigned long</code> but checks that the passed value
+fits in $c size_t. In other words, if you call $c GetMemory()
+with a size of 65,536 the 16-bit DOS version will trigger a
+fatal error immediately instead of silently allocating 1 byte
+and letting you search afterwards why the program behaves
+strangely. A better fix would be to make $c GetMemory() call $c
+GetFarMemory() when the block is too large for $c malloc(). Any
+volunteers ?
+
+<p>Memory allocated with $c GetMemory() is guaranteed to be
+freeable with $c free().  On the other hand, memory allocated
+with $c GetFarMemory() must be freeed with $c FreeFarMemory().
+
+			<h3><a name="endianness">Endianness</a></h3>
+
+The 16-bit and 32-bit integers in a wad file are always
+little-endian, whatever the platform.
+
+<p>On the other hand, Yadex keeps all its in-core integer in the
+platform's native endianness, i.e. in little-endian format on
+little-endian machines and in big-endian format on big-endian
+machines.
+
+<p>The wad endianness &lt;-&gt; native endianness conversion is
+done automagically by $c wad_read_i16() and $c wad_read_i32().
+
+<p><u>To maintain compatibility with big-endian platforms, all
+I/O of multibyte integers should be done with those
+functions.</u>
+
+		<h2>The directory</h2>
+
+			<h3>Principle</h3>
+
+Like Doom, Yadex accesses lumps through an indirection layer
+that called the <i>directory</i>. The directory is basically a
+list of all the lumps that exist in the iwad and/or at least one
+of the pwads with, for each lump, the information necessary to
+read it. Each directory entry has 4 fields&nbsp;; the name of
+the lump, its offset in the wad, its length, and an indirect
+pointer to the file descriptor for the wad that contains it.
+
+<p>As you might expect, if the same lump is present in more than
+one wad, it has only one directory entry, pointing to the last
+occurence.
+
+<p>When you need to load a lump by name, you call
+<code>FindMasterDir()</code>.  It returns you a pointer on its
+entry in the directory, which in turn contains everything you
+need to read it.
+
+			<h3>Managing the directory</h3>
+
+<p>The directory is kept in memory at all times. It is only
+modified when you initially load the iwad and when you load or
+unload a pwad. And of course when you delete the directory.
+Simple, isn't it&nbsp;?
+
+<p>Ha-ha, gotcha, this is not how the actual API works. The
+actual set of operations is somewhat different in that it does
+not include unloading a pwad. Instead, there is a function to
+close all unused pwads, that is pwads that are not referenced by
+a single entry in the directory. I suppose that the reason why
+it was done this way is that unloading a pwad is a bit more
+complicated, since it involves finding the previous "provider"
+of all lumps that the wad to unload used to "provide". I guess
+the only way to do that would be rebuilding the directory from
+scratch. This "feature" is discussed in the Comments section
+below. Anyway, here is the API.
+
+<dl>
+<dt><code>OpenMainWad()</code>
+<dd>Create the directory and fill it with the contents of the
+directory of the iwad.
+
+<dt><code>OpenPatchWad()</code> 
+<dd>Add a pwad to the list of the open wads and to the
+directory.
+
+<dt><code>CloseUnusedWadFiles()</code>
+<dd>Close all wads that are not used in the directory anymore.
+
+<dt><code>CloseWadFiles()</code>
+<dd>Close all open wads and delete the list of open wads and the
+directory.
+</dl>
+
+			<h3>Implementation</h3>
+
+It has not been said explicitly so far but Yadex maintains a
+list of all open wads (iwads and pwads). It is a linked list of
+the <code>WadFileInfo</code> structure. The global variable
+<code>WadeFileList</code> is a pointer to the first element of
+the list, which is always the iwad. The type <code>WadPtr</code>
+is an alias for "<code>struct WadFileInfo *</code>" (yes, I
+know, it's confusing to have two names for the same thing).
+
+<pre>
+struct WadFileInfo
+   {
+   WadPtr next;                 // Next file in linked list
+   char *filename;              // Name of the wad file
+   FILE *fd;                    // C file stream information
+   char type[4];                // Type of wad file ("IWAD" or "PWAD")
+   i32  dirsize;                // Directory size of wad
+   i32  dirstart;               // Offset to start of directory
+   DirPtr directory;            // Array of directory information
+   };
+typedef struct WadFileInfo *WadPtr;
+extern WadPtr WadFileList;      // List of wad files
+</pre>
+
+<p>The directory itself is a linked list of the
+<code>MasterDirectory</code> structure. The global variable
+<code>MasterDir</code> points to the first element of the
+directory. The type <code>MDirPtr</code> is an alias for
+"<code>struct MasterDirectory *</code>".
+
+<pre>
+struct Directory
+   {
+   i32  start;                  // Offset to start of data
+   i32  size;                   // Byte size of data
+   char name[WAD_NAME];         // Name of data block
+   };
+struct MasterDirectory
+   {
+   MDirPtr next;                // Next in list
+   WadPtr wadfile;              // File of origin
+   struct Directory dir;        // Directory data (name, offset, size)
+   };
+typedef struct MasterDirectory *MDirPtr;
+extern MDirPtr MasterDir;       // The master directory
+</pre>
+
+			<h3>Sample code</h3>
+
+To be written : searching for a directory entry. The same thing,
+in an incremental fashion.
+
+			<h3>Comments</h3>
+
+<p>The decision to use a directory is arguable. It is convenient
+for the programmer when he/she is looking for the
+<em>effective</em> instance of a lump, which is the case most of
+the time. But it also prevents the user from editing a resource
+(notably, a level), if it has been overridden in another wad.
+It's not a big deal but I don't like it.
+
+<p>The fact that the directory managing operations don't include
+removing a pwad from the directory means that there is no way
+for the user to "unload" a pwad. The "<code>read</code>" command
+has no inverse. The only way to do it is to restart Yadex.
+
+<p>Another somewhat non obvious design decision is that, in most
+places where the directory is updated,
+<code>CloseUnusedWadFiles()</code> is called too. This means
+that you can't load two pwads that have exactly the same lumps.
+As the second pwad is loaded, the first one is automatically
+(and silently) unloaded. Not a big deal either but, as a user, I
+don't like the programs I use to behave like that. I'll
+illustrate my point with the following scenario, which assumes
+the "unload pwad" function exists&nbsp;:
+<ol>
+<li>Load pwad A (MAP01)
+<li>Load pwad B (MAP01)
+<li>Unload pwad B
+<li>Edit MAP01
+</ol>
+At this point, as you have backtracked on your action of loading
+B, you would expect to see the MAP01 from A, wouldn't you&nbsp;?
+Instead you get the MAP01 from the iwad, because A was unloaded
+as you loaded B. From a user point of view, such a behaviour is
+confusing and therefore to be avoided.
+
+<p>I don't like the directory management API very much because
+it's unexpectedly asymmetric and therefore neither intuitive nor
+orthogonal. The way Yadex plays games with the directory is
+really disgusting and confusing to me.
+
+<p>I should look into replacing the iwad "on the fly", so that
+the user is able to change the game parameter dynamically,
+without restarting Yadex. In fact, the ultimate goal is to
+remove the game parameter completely or, more precisely, to make
+it local to a Level object, automatically adjusting and
+dynamically modifiable by the user.
+
+		<h2>The wad data</h2>
+
+TBD
+
+		<h2>The level data</h2>
+
+			<h3>Structure</h3>
+
+The data for a level is stored in 10 variables
+that are declared in <code>levels.h</code> and
+defined in <code>levels.cc</code>. Here they are :
+<pre>int   NumThings;         /* number of things */
+TPtr  Things;            /* things data */
+int   NumLineDefs;       /* number of linedefs */
+LDPtr LineDefs;          /* linedefs data */
+int   NumSideDefs;       /* number of sidedefs */
+SDPtr SideDefs;          /* sidedefs data */
+int   NumVertices;       /* number of vertices */
+VPtr  Vertices;          /* vertices data */
+int   NumSectors;        /* number of sectors */
+SPtr  Sectors;           /* sectors data */</pre>
+
+			<h3>Scope and lifetime</h3>
+
+Since those variables (and other critical ones)
+are unfortunately static, it's not possible to
+open editing windows on several different levels
+simultaneously.
+This should be fixed in the future by making the
+level data a class and turning those variables
+into members of that class.
+<p>
+I think that the level data class should be separate
+from the editing window class because it might be
+useful to open several editing windows on the same
+level.
+Separate class should also make the design of the read
+level and write level routines cleaner and simpler.
+
+			<h3>Maintenance</h3>
+
+It's of paramount importance for the stability and
+reliability of Yadex that the level data be maintained
+in a consistent state at all times. In particular,
+<ul>
+<li>the $c Num* variables must remain accurate,
+<li>vertex references in linedefs must be either
+	$c OBJ_NO_NONE or the number of an existing vertex,
+<li>sidedef references in linedefs must be either
+	$c OBJ_NO_NONE or the number of an existing sidedef,
+<li>sector references in sidedefs must be either
+	$c OBJ_NO_NONE or the number of an existing sector.
+</ul>
+
+			<h3>Loading</h3>
+
+The SEGS, SSECTORS, NODES, BLOCKMAP and REJECT lumps are
+ignored. The other lumps are read into the level data
+variables with a special case for VERTEXES ; vertices
+that are not used by any linedef are ignored (such vertices
+are believed to come from the nodes builder and therefore
+be irrelevant to level editing). The linedefs vertices
+references are updated if necessary.
+<p>
+Since the endianness of the wad files is fixed (little
+endian) and thus not necessarily identical to the endianness
+of the CPU, reading 2- and 4-byte integers from the file is
+done through special endianness-independant routines.
+
+			<h3>Saving</h3>
+
+If $c MadeMapChanges is false, the SEGS, SSECTORS, NODES,
+BLOCKMAP, REJECT and VERTEXES lumps are copied from the
+original file. Else, they are output with a length of
+zero bytes, except the VERTEXES lump that is created
+from the the level data ($c NumVertices and $c Vertices).
+
+<p>Since the endianness of the wad files is fixed (little
+endian) and thus not necessarily identical to the endianness of
+the CPU, writing 2- and 4-byte integers to the file is done
+through special endianness-independant routines.
+
+		<h2>Editing windows, or the lack of it</h2>
+
+Too many global variables...
+<p>
+See "<code>_edit.h</code>".
+
+		<h2>The editor loop</h2>
+
+All the time the user spends editing a level is
+spent within a certain function, the <dfn>editor loop</dfn>,
+a.k.a. $c EditorLoop() in $c editloop.c.
+It's essential for you to understand it
+if you want to get how Yadex works right.
+<p>
+The $c EditorLoop() is an endless loop (okay, not
+<em>really</em> endless) which, for each iteration,
+first, refreshes the display,
+second, waits for an event,
+third, processes that event.
+I could have put things in a different order
+but I liked the idea of displaying something
+<em>before</em> waiting for user input.
+<p>
+Because the event input and the graphical output
+are complex and not-quite-synchronous processes,
+I've tried to separate them.
+$c EditorLoop() gets input events and processes them
+and calls another function, $c edisplay_c::refresh(),
+to take care of everything display related.
+If you replaced $c edisplay_c::refresh() by a stub
+(and did the same with a couple of functions in $c gfx.c
+and $c input.c), you could perfectly well, if blindly,
+run Yadex without a connection to an X server.
+While you may object that this would be a pointless exercise
+(to which I agree), it still proves the modularity of the design.
+<p>
+The $c edisplay_c::refresh() function
+is also a very important one to understand,
+at least if you work on graphical output.
+It is discussed in another section but,
+just to settle ideas, I thought I'd give you
+here a bird's eye view of the whole thing.
+If there is a single paragraph in this document
+that you need to read, it's probably this one :
+<ul>
+<li>$c EditorLoop()
+	<ul>
+	<li>Call $c edisplay_c::refresh(),
+		<ul>
+		<li>Do some basic geometry management,
+		<li>setup widgets according to editing session,
+		<li>call the $c need_to_clear() method of the widgets
+			to determine whether we need to redisplay
+			everything from scratch,
+		<li>if so, call the $c clear() method of the widgets
+			and call $c ClearScreen() to clear the pixmap
+			(if available) and make
+			sure all subsequent graphical output will be sent
+			to the pixmap (if available),
+		<li>else, make sure all subsequent graphical ouput will
+			be sent to the window and call the $c undraw()
+			method of the widgets from the top down,
+		<li>call the $c draw() method of the widgets from the bottom up,
+		<li>call $c update_display() to refresh the physical display
+			(if we're using the window, it's a no-op,
+			if we're using the pixmap, call $c XCopyArea()).
+		</ul>
+	<li>call $c get_input_status() to get the next event,
+	<li>process that event.
+	</ul>
+</ul>
+
+Note that all graphical output is done from within $c edisplay_c::refresh().
+
+		<h2>The display</h2>
+
+			<h3>Logical and physical display : widgets</h3>
+
+The display can be seen at two levels ;
+the logical level and the physical level.
+The physical level is just a rectangular
+matrix of pixels. It's the contents of
+the window/screen.
+The logical level is more like "oh, there's
+a window displayed at those coordinates".
+<p>
+There's obviously more to say on this...
+
+			<h3>The pixmap</h3>
+
+To further complicate matters,
+there are two physical displays :
+a window and a pixmap.
+The role of the pixmap is to help avoid flicker.
+Here's how it works :
+<p>
+As long as we do incremental changes to the display
+(E.G. "undisplaying" the highlight on a vertex
+or redisplaying the pointer coordinates),
+we do it directly on the window.
+<p>
+But, if we have to redraw everything from scratch,
+we have to clear the window first which generates
+an annoying "flashing" of the screen.
+To avoid this, we instead clear a pixmap,
+do our display thing on it and then
+put the pixmap onto the window, with $c XCopyArea().
+The result is a flicker-less refresh.
+<p>
+The graphical routines from $c gfx.c
+switch automatically to the pixmap if
+$c ClearScreen() was called.
+Thanks to this, that window vs. pixmap thing
+is nearly transparent to the application functions.
+$c edisplay_c::refresh() just forces
+widgets that can undraw themselves to use the
+window, not the pixmap.
+<p>
+But a pixmap is large.
+For a 800x600 window in 64k colours, 937 kB.
+And copying it to the window is obviously long.
+So, on machines with little memory or a slow CPU,
+the user might prefer to do without it.
+That's what $c no_pixmap is for.
+
+		<h2>The selection</h2>
+
+			<h3>Introduction</h3>
+
+From the user's point of view, the selection is a "list" of
+objects.  I use the term "list" instead of "collection" because,
+for certain operations, the order in which objects were added to
+the selection is significant.
+<p>
+From the programmer's point of view, the selection is a
+singly linked list of objects of this type :
+<p>
+<pre>typedef struct SelectionList *SelPtr;
+struct SelectionList
+   {
+   SelPtr next;                 /* next in list */
+   int objnum;                  /* object number */
+   };</pre>
+<p>
+Note that the $c SelectionList structure
+has no $c objtype field ;
+the type of the object (THING, vertex...)
+is implicit from the current mode
+(the $c obj_type field from the $c edit_t
+structure).
+As a consequence, the selection cannot contain
+objects of different types.
+<p>
+The selection manipulation functions are supposed to be
+defined in $c selectn.c and declared in
+$c selectn.h. Here they are :
+
+<dl>
+<dt><code>void SelectObject (SelPtr *s, int n)</code>
+<dd>Adds object $c n at the beginning of list $c *s.
+$c *s can be $c NULL ; it means the list is empty.
+Warning : does not check that object $c n is not already
+in the list.
+
+<dt><code>void UnSelectObject (SelPtr *s, int n)</code>
+<dd>Removes from list $c *s all occurrences of
+object $c n.
+If all objects are removed, sets $c *s to $c NULL.
+
+<dt><code>void select_unselect_obj (SelPtr *s, int n)</code>
+<dd>If the object $c n is already in the list $c *n, remove it.
+If it's not, insert it at the beginning.
+$c *s can be $c NULL ; it means the list is empty.
+
+<dt><code>Bool IsSelected (SelPtr s, int n)</code>
+<dd>Tells whether object $c n is in selection $c s.
+$c s can be $c NULL ; it means the list is empty.
+
+<dt><code>void ForgetSelection (SelPtr *s)</code>
+<dd>Frees all memory allocated to list $c *s
+and sets $c *s to $c NULL.
+
+<dt><code>void DumpSelection (SelPtr s)</code>
+<dd>Debugging function ; prints the contents of the
+selection to $c stdout.
+</dl>
+
+Note that there is not selection iteration function.
+Indeed, iterating through a selection is always done
+by the application functions themselves, usually with
+something like :
+<p>
+<pre>SelPtr cur;
+for (cur = list; cur; cur = cur-&gt;next)
+   do_something_with_object (cur-&gt;objnum);
+</pre>
+
+			<h3>Selecting in/out</h3>
+
+When you draw a box with [<kbd>Ctrl</kbd>] depressed, the objects in
+the box are added to the selection.
+However, if some of those objects were already selected,
+they are unselected.
+So $c SelectObjectsInBox() cannot just add all
+the objects in the box to the list or we would end up with
+multiply selected objects. Wouldn't do us much good when
+displaying the selection or dragging objects.
+<p>
+That's when $c select_unselect_obj() is used.
+
+		<h2>The highlight</h2>
+
+TBD
+
+		<h2>Colours</h2>
+
+The colour management system in very complex.
+There are lots of things to say on that topic.
+However, for most uses, you need to know only three functions :
+<dl>
+<dt>$c set_colour()
+<dd>Set the current colour to a new value.
+<dt>$c push_colour()
+<dd>Save the current colour on the colour stack
+and set the current colour to a new value.
+<dt>$c pop_colour()
+<dd>Set the current colour to the value
+it had at the moment of the last call to $c push_colour().
+</dl>
+
+		<h2>Menus and pop-up windows</h2>
+
+TBD
+
+		<h2>Game graphics</h2>
+
+			<h3>Doom graphics basics</h3>
+
+Doom and its derivatives have two main formats for
+graphics&nbsp;: pictures and plain bitmaps. Pictures are made of
+columns which are in turn made of one or more posts. If there
+are several posts in a column, they can be separated by void
+space and thus the picture can have transparent areas. Pictures
+are used for patches, sprites and the rest of the graphics (but
+Yadex doesn't use them). Plain bitmaps are just arrays of pixels
+and cannot contain transparent areas. That latter format is used
+only for flats, which are all 64&times;64 bitmaps.
+
+<p>Textures are made by pasting one or more patches onto a
+rectangular buffer. The resulting image can be of course
+transparent.
+
+<p>For all formats, a pixel is a byte. The value of the byte
+(between 0 and 255 inclusive) is an index into one of the
+palettes contained in the <code>PLAYPAL</code> lump. To be able
+to know the actual RGB colour of a pixel, it is necessary to
+look up its value in the <code>PLAYPAL</code> (normally, only
+the first palette is used).
+
+			<h3>The <code>Img</code> class</h3>
+
+<p>The <code>Img</code> class is used to store and manipulate
+all game graphics (flats, patches, sprites and textures). It's a
+palette-encoded rectangular array of pixels. The type
+<code>img_pixel_t</code> is the type of a pixel; it's the same
+as in the wad, that is a byte. The value of the elements of the
+array is also the same as in the wad, that is an index into
+<code>PLAYPAL</code>. Transparent areas are filled with colour
+number 0 (which translates to black with all known iwads).
+Unfortunately, colour 0 is also used in certain graphics which
+causes them to be rendered with holes in them. This needs to be
+fixed.
+
+<p>The related functions are&nbsp;:
+<pre>Img::Img             - default constructor
+Img::Img             - constructor with dimensions
+Img::~Img            - dtor
+Img::is_null         - return true iff this is a null image
+Img::width           - return the current width
+Img::height          - return the current height
+Img::buf             - return a const pointer on the buffer
+Img::wbuf            - return a writable pointer on the buffer
+Img::resize          - resize the image
+clear_img            - clear a game image buffer
+display_img          - display a game image
+scale_img            - scale a game image
+spectrify_img        - make a game image look vaguely like a spectre
+LoadPicture          - read a picture from a wad file into an Img object</pre>
+
+			<h3>Viewing graphics</h3>
+
+<p>As is the case with saving graphics to a file, viewing
+graphics would involve a lot of coding to do it in an optimized
+fashion. Therefore it's done in a somewhat wasteful way&nbsp;:
+
+<ol>
+  <li>the image is put into an <code>Img</code> object
+  <li>the <code>Img</code> is pasted onto the window or screen
+</ol>
+
+<p>The first step is done with
+<code>DisplayFloorTexture()</code> (for flats) and
+<code>LoadPicture()</code> (for other graphics). For textures,
+<code>LoadPicture()</code> is called repeatedly on the same
+<code>Img</code> object, once for each flat.
+
+<p>The second step is done with
+<code>display_img()</code>. It takes care of converting
+Doom pixel values into actual pixel values needed by the
+graphical API (which depend on a lot of factors like the video
+mode, type and depth of visual, byte order of X server, etc.)
+and getting the graphical API to display it on the window or
+screen.
+
+<p><code>display_pic()</code> combines fetching the image into
+the game image buffer and displaying it.
+
+<p><code>spectrify_img()</code> can be used on a game
+image buffer to make it look more or less like a spectre.
+
+			<h3>Saving graphics to file (screenshots etc.)</h3>
+
+The basic idea is to
+
+<ol>
+  <li>get the image to save in an <code>Rgbbmp</code> buffer (with
+    <code>window_to_rgbbmp()</code>),
+  <li>save the <code>Rgbbmp</code> buffer to a file (with
+    <code>rgbbmp_to_ppm()</code>).
+</ol>
+
+This is inefficient because, in many cases, the image could be
+saved directly from the window to the file. This two-step
+algorithm wastes memory (the buffer can be quite large) and
+time. However, there is a good reason for doing things this way.
+
+<p>The way to retrieve the image from the window or screen is
+very dependent on the platform or video mode or type of visual
+and the fashion in which the image is read is very dependent on
+the graphic format. Therefore, if you want to use a one-step
+algorithm and you have <var>n</var> platforms or video modes or
+types of visuals and <var>m</var> graphic formats, you have to
+write <var>n</var> &times; <var>m</var> functions. With a
+two-step algorithm, you have only <var>n</var> + <var>m</var>
+functions to write. As saving graphics to file is not a critical
+function, I'd rather keep the code short and simple, unless the
+result proves unacceptable.
+
+		<h2>Saving</h2>
+
+<p>One very important constraint in the saving code is that it
+should never fail unless there is no reasonable alternative.
+That's because, for users, saving is a <em>passage
+obligé</em> to quit the program without losing their work.
+Therefore, the saving code must be particularly robust and able
+to recover from errors.
+
+<p>This implies that the saving code <strong>must not need to
+allocate new memory</strong>. To understand why, consider the
+following scenario&nbsp;: you load a level and edit it until
+Yadex uses all the available memory save a few kB. Then you want
+to save it and Yadex says "nope, I don't have enough memory to
+do that". From a user point of view, that sucks.
+
+<p>Unfortunately, at present, many benign errors are considered
+fatal when saving. For example, trying to save to a file on
+which you don't have the necessary rights will make Yadex abort
+even though this error is perfectly recoverable. This should be
+fixed since it could cause users to lose data.
+
+		<h2>Compile-time variables (defines)</h2>
+
+<dl>
+<dt>$c AYM_MOUSE_HACKS
+<dd>Some experimental code by me to try to understand why,
+under DOS, the mouse pointer moves 8 pixels at a time
+(seems to depend on the mouse driver ?).
+<p>
+<dt>$c CIRRUS_PATCH
+<dd>Dates back to DEU 5.21. Apparently, some code specific to
+Cirrus VGA boards.
+Does nothing unless $c Y_BGI is defined.
+<p>
+<dt>$c DEBUG
+<dd>The obvious.
+<p>
+<dt>$c DIALOG
+<dd>Experimental code by me to test the dialog box function
+that Jim Flynn wrote for Deth in the beginning of 1998.
+<p>
+<dt>$c NO_CIRCLES
+<dd>If your BGI driver does not support drawing circles,
+define this and Yadex will draw squares instead.
+<p>
+<dt>$c OLD
+<dd>Misc. obsolete stuff I didn't want to delete at the time.
+Never define it or you'll break Yadex&nbsp;!
+Code under <code>#ifdef OLD</code> should probably be removed.
+<p>
+<dt>$c OLD_GRID
+<dd>Pre-1.5 grid (no dots, only lines).
+<p>
+<dt>$c OLD_METHOD
+<dd>My cruft. Code thus <code>#ifdef</code>'d should probably be removed.
+<p>
+<dt>$c OLD_MESSAGE
+<dd>My cruft. Code thus <code>#ifdef</code>'d should probably be removed.
+<p>
+<dt>$c ROUND_THINGS
+<dd>Draw THINGS as circles (like DEU did), not as squares.
+<p>
+<dt>$c SWAP_TO_XMS
+<dd>Comes from DEU : related to code supposed to use XMS as
+"swap space". Apparently, was never used ?
+<p>
+<dt>$c Y_BGI
+<dd>Use BGI for graphics output and BIOS for keyboard and mouse
+input. Makes senses only for DOS + Borland C++ 4.0.
+Exactly one of ($c Y_BGI, $c Y_X11) must be defined.
+<p>
+<dt>$c Y_DOS
+<dd>Compile for DOS (with Borland C++ 4.0). Allows, among others,
+the $c huge and $c far pointer modifiers.
+Exactly one of ($c Y_DOS, $c Y_UNIX) must be defined.
+<p>
+<dt>$c Y_UNIX
+<dd>Compile for Unix (with GCC 2.7.2). Causes, among other
+things, "huge" and "far" to be <code>#define</code>'d to "".
+Exactly one of ($c Y_DOS, $c Y_UNIX) must be defined.
+<p>
+<dt>$c Y_X11
+<dd>Use X11 (Xlib) for graphics output, keyboard and mouse
+input and other events.
+Exactly one of ($c Y_BGI, $c Y_X11) must be defined.
+</dl>
+
+		<h2>Coding standards</h2>
+
+Warning : this section was written when Yadex was still plain C.
+Some of it may be inadequate or incomplete with C++.
+
+			<h3>Indent style</h3>
+
+BSD style with an indent width of 2.
+<ul>
+<li>tab stops every 8 characters,
+<li>indent width is 2 spaces,
+<li>line width limited to 80 characters,
+<li>the braces have the same indentation as the text they contain,
+<li>the body of a function is not indented.
+</ul>
+
+Many files still use Whitesmiths with an indent width of 3. They
+will be reformatted.
+
+Whitespace&nbsp;:
+<ul>
+<li>one space between the name of the function/statement and the "(",
+<li>no space between the "(" and the first argument,
+<li>no space between the end of the argument and the "," or ";",
+<li>one space between the "," or ";" and the next argument,
+<li>no space between the end of the argument and the ")",
+<li>no space between the ")" and the ";",
+<li>no space between the name of a variable and a "<code>[</code>",
+<li>no space between a "<code>[</code>" and the character that follows,
+<li>no space between a "<code>]</code>" and the character that precedes,
+<li>one space on either side of binary operators,
+<li>the dereferencing operator ("<code>*</code>") has a space to the left but
+  no space to the right.
+</ul>
+
+<p>
+Example :
+<p>
+<pre>static const char *foo (int n)
+{
+  for (stuff; stuff; stuff)
+  {
+    if (thingie || gadget ())
+      call_this_one (with, three, exactly[arguments]);
+    else
+      dont ();
+    call_that_one ();
+  }
+  return NULL;
+}</pre>
+
+			<h3>Identifiers</h3>
+
+For variables and functions (and certain macros),
+I use all-lower-case identifiers
+with underscores where it seems appropriate.
+For enums and most macros,
+I use all-upper-case identifiers.
+<p>
+I consistently use the English spelling (E.G. "colour", not "color").
+
+			<h3>Conditionals</h3>
+
+The argument of <code>if</code> and <code>while</code> and the
+second argument of <code>for</code> are booleans, not integers,
+so you should provide a boolean expression. The following
+expressions are not booleans&nbsp;:
+
+<ul>
+  <li>pointers,
+  <li>the return value of <code>strcmp()</code>,
+  <li>the return value of functions to return 0 to indicate
+  success and non-zero to indicate failure,
+</ul>
+
+Therefore, don't write
+
+<p><pre>
+if (! fopen (filename, "r"))  // Test for failure
+  ...
+if (strcmp (str1, str2))  // Test for non-equality
+  ...
+if (! strcmp (str1, str2))  // Test for equality
+  ...
+if (remove (filename))  // Test for failure
+  ...
+</pre></p>
+
+but
+
+<p><pre>
+if (fopen (filename, "r") <b>== NULL</b>)
+  ...
+if (strcmp (str1, str2) <b>!= 0</b>)
+  ...
+if (strcmp (str1, str2) <b>== 0</b>)
+  ...
+if (remove (filename) <b>!= 0</b>)
+  ...
+</pre></p>
+  
+On the other hand, when an expression is a boolean, you don't
+need to add anything. <i>Don't</i> write <code>if (boolvar ==
+true)</code>.
+
+			<h3>General style</h3>
+
+My general style is to try to make it look clear and pretty. If there
+are several similar consecutive statements, I try to align what I can.
+<p>
+<pre>/* This is a long comment. A long comment is a comment
+   that spans over several lines. See how I "typeset" it. */
+func         (object, mutter    );
+another_func (object, mumble, 46);
+yet_another  (object, grunt     );  // Short comment.</pre>
+
+			<h3>Code</h3>
+
+Good code ;-).
+<p>
+<ul>
+<li>Use $c const for all arguments passed by reference
+unless they're modified.
+<li>Use $c static for all functions and variables
+unless they're extern.
+<li>Be careful with $c int,
+on some platforms, it's equivalent to $c short,
+on others, it's equivalent to $c long.
+<li>Whenever you need a fixed number of bytes,
+use $c u16, $c i32, etc.
+<li>Use prototypes.
+<li>Prototype functions that take no args with "<code>foo (void);</code>",
+ not "<code>foo ();</code>" (author's note : this is C-ish !).
+<li>Try to avoid buffer overruns
+by using $c y_snprintf() instead of $c sprintf(),
+$c al_scps() instead of $c strcpy(),
+$c al_saps() instead of $c strcat(), etc.
+</ul>
+
+			<h3>Functions to avoid</h3>
+
+<dl>
+  <dt><b><code>sprintf()</code></b>
+  <dd>Prone to buffer overruns. Use <code>y_snprintf()</code> instead, as it
+    uses <code>snprintf()</code> if it's available, and falls back on
+    <code>sprintf()</code> if it isn't.
+
+  <dt><b><code>snprintf()</code></b>
+  <dd>Not supported widely enough yet. Use <code>y_snprintf()</code> instead.
+    If <code>snprintf()</code> is available, it uses it (well, at least that's
+    what it's meant to do). If not, it falls back on <code>sprintf()</code>.
+
+  <dt><b><code>stricmp()</code></b> and <b><code>strcasecmp()</code></b>
+  <dd>Not portable. Use <code>y_stricmp()</code> instead.
+    <code>y_strnicmp()</code> is available as well.
+
+</dl>
+
+			<h3>Use the helpers</h3>
+
+<dl>
+  <dt><b>Converting an ASCII digit into its value</b>
+  <dd>Don't subtract <code>'0'</code>. Use <code>dectoi()</code> or
+    <code>hextoi()</code>.
+
+  <dt><b>Testing whether a value is comprised between two bounds</b>
+  <dd>Instead of <code>v &gt;= min &amp;&amp; v &lt;= max</code> you can use
+    <code>within (v, min, max)</code>. It's inlined. The inverse test is
+    provided by <code>outside()</code>.
+
+  <dt><b>Comparing two file names</b>
+  <dd>If you come from a Unix background, you'll be tempted to use
+    <code>strcmp()</code>. If you come from a DOS background, you'll be tempted
+    to use <code>y_stricmp()</code>. Neither is correct. Use
+    <code>fncmp()</code>. In its current implementation, it's not correct
+    either but it gets you a little bit closer. If only because it helps you
+    to say what you mean.
+
+  <dt><b>Telling whether is file name is absolute</b>
+  <dd>This is not needed in many places. But when it is, use
+    <code>is_absolute()</code>.
+
+  <dt><b>Comparing two lump names</b>
+  <dd>The code is peppered with <code>y_strnicmp(name1, name2,
+    WAD_NAME)</code>. This should of course be replaced by a specialized
+    function. This also applies to comparing flat names, texture names, sprite
+    names, patch names, etc.
+
+</dl>
+
+			<h3>Includes</h3>
+
+Put $c yadex.h first,
+then any standard headers needed (E.G. $c math.h)
+then all the Yadex headers needed by alphabetical order.
+<p>
+If the need arises to protect a Yadex header against multiple inclusion,
+use this :
+<p>
+<pre>#ifndef YH_FOO
+#define YH_FOO
+(put the contents of the header here)
+#endif</pre>
+
+			<h3>File format</h3>
+
+<table width="100%" bgcolor="#90a0c0" cellpadding="8">
+  <tr>
+    <td>
+      The format of the source files is&nbsp;:
+      <table cellspacing="0" cellpadding="0">
+        <tr>
+	  <td>
+	    <ul>
+	      <li>Character set&nbsp;
+	      <li>Line length&nbsp;
+	      <li>Line terminator&nbsp;
+	      <li>Tab width&nbsp;
+	    </ul>
+	  </td>
+	  <td>
+	    ISO 8859-1 (a.k.a. Latin1)
+	    <br>80 columns
+	    <br>LF
+	    <br>8
+	  </td>
+	</tr>
+      </table>
+</table>
+
+		<h2>Notes</h2>
+
+Here is the text of the notes in the source code.
+<p>
+<dl>
+<dt>1
+<dd>It's important to set the $c line_width to 1
+and not 0 for GCs that have the $c GXxor function,
+for the following reason.
+<p>
+Those GCs are used for objects that should be "undrawn" by
+drawing them again, E.G. the highlight.
+Now, imagine the following scenario :
+you highlight a linedef and then press, say, page up to
+make the window scroll. This is not an incremental change
+to the display so everything is redrawn from scratch onto
+the pixmap. The pixmap is <code>XCopyArea()</code>'d onto the window,
+the linedef still highlighted. Then, Yadex realizes that
+the map coordinates of the pointer have changed so the
+linedef is not highlighted anymore. It dutifully unhighlights
+the linedef. But $c XDrawLine() on a window does not use the
+same algorithm as on a pixmap (attempts to use the blitter
+on the video card). So the first line and the second don't
+coincide exactly and the result is a trail of yellow pixels
+where the highlight used to be.
+<p>
+That's why I use a $c line_width
+sure that the same algorithm is used both for pixmap output
+and for window output.
+
+</dl>
+
+<p><hr>AYM $SELF_DATE
+</body>
+</html>
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/docsrc/help.html	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,32 @@
+<html>
+<head>
+<title>Getting help</title>
+</head>
+<body>
+
+<div align="center">
+<img src="logo_small.png" alt="Fancy logo">
+<br>Yadex $VERSION ($SOURCE_DATE)
+<h1>Getting help</h1>
+</div>
+<br>
+<br>
+<br>
+
+<p>The preferred place to put a question about Yadex is the <a
+href="contact.html#list_yadex"><code>yadex</code></a> mailing
+list.
+
+<p>Do <em>not</em> mail the maintainer. Yes, this means you.
+Send all mail to the list.</p>
+
+<p>General Doom editing questions are better answered on <a
+href="news:rec.games.computer.doom.editing">
+<code>rec.games.computer.doom.editing</code></a> or in one of
+the many fine Doom editing tutorials and books (see the <a
+href="editing_docs.html">list</a>).
+
+</p><hr>AYM $SELF_DATE
+
+</body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/docsrc/index.html	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,72 @@
+<html>
+<head>
+<title>Yadex documentation</title>
+</head>
+<body>
+
+<div align="center">
+<img src="logo.png" alt="Fancy logo">
+<br>Yadex $VERSION ($SOURCE_DATE)
+<h1>Yadex documentation</h1>
+</div>
+
+	<h2>Read this first</h2>
+
+<ul>
+<li><a href="../README">How to compile and install Yadex</a>
+<li><a href="../CHANGES">What's new in this release</a>
+<li><a href="getting_started.html">Getting started</a>
+<li><a href="users_guide.html">User's guide</a>
+<li><a href="tips.html">Tips</a>
+<li><a href="faq.html">FAQ</a>
+</ul>
+
+	<h2>Any trouble ?</h2>
+
+<ul>
+<li><a href="trouble.html">Troubleshooting</a>
+<li><a href="reporting.html">Reporting bugs</a>
+<li><a href="help.html">Getting help</a>
+<li><a href="faq.html">FAQ</a>
+</ul>
+
+	<h2>Additional documents</h2>
+
+<ul>
+<li><a href="palette.html">Palette viewer</a>
+<li><a href="advanced.html">Advanced user's guide</a>
+<li><a href="../TODO"><code>TODO</code></a>
+<li><a href="yadex.6">The man page for Yadex</a>
+<li><a href="ygd.html">Yadex game definition files</a>
+<li><a href="wad_specs.html">Wad specs</a>
+<li><a href="hackers_guide.html">Hacker's guide</a>
+<li><a href="packagers_guide.html">Packager's guide</a>
+<li><a href="deu_diffs.html">Differences between Yadex and DEU 5.21</a>
+</ul>
+
+	<h2>Non-technical information</h2>
+<ul>
+<li><a href="keeping_up.html">Keeping up to date</a>
+<li><a href="feedback.html">User feedback</a>
+<li><a href="contact.html">Contact information</a>
+<li><a href="credits.html">Credits</a>
+<li><a href="trivia.html">Trivia</a>
+</ul>
+
+	<h2>General Doom information</h2>
+
+<ul>
+<li><a href="editing_docs.html">Doom editing docs and tutorials</a>
+</ul>
+
+	<h2>Legal</h2>
+
+<ul>
+<li><a href="legal.html">Legal notices</a>
+<li><a href="../COPYING">The GPL (GNU General Public License)</a>
+<li><a href="../COPYING.LIB">The LGPL (GNU Library General Public License)</a>
+</ul>
+
+</body>
+</html>
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/docsrc/keeping_up.html	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,48 @@
+<html>
+<head>
+<title>Keeping up to date</title>
+</head>
+<body>
+
+<div align="center">
+<img src="logo_small.png" alt="Fancy logo">
+<br>Yadex $VERSION ($SOURCE_DATE)
+<h1>Keeping up to date</h1>
+<table><tr><td></td><td width="50%" align="center">
+How you can know when a new version comes out without having to
+watch the homepage.
+<td></td></table>
+</div>
+<br>
+<br>
+<br>
+
+<p>In spite of my efforts, new versions of Yadex tend to pop up
+every now and then. But don't be afraid, I'm vigilant. As soon
+as I see one coming, I raise the alarm on the <a
+href="contact.html#list_yadex-announce"><code>yadex-announce</code></a>
+mailing list. You should have enough time to run for cover.
+
+<p>I'm also likely to post an announcement on <a
+href="news:rec.games.computer.doom.editing"
+><code>rec.games.computer.doom.editing</code></a> and <a
+href="http://freshmeat.net">Freshmeat</a>. Several news sites
+such as <a href="http://www.doomcenter.com/">Doom center</a>, <a
+href="http://www.doomworld.com/">Doomworld</a>, <a
+href="http://www.happypenguin.org/">Linux Game Tome</a>, <a
+href="http://www.newdoom.com/">New Doom</a> and <a
+href="http://www.linuxgames.com/">Linuxgames</a> have been
+witnessed to echo the announcements.
+
+<p>To download the latest version, see the <a
+href="contact.html#homepage">Yadex home page</a>.
+
+<p>To know what's cooking (that is <em>if</em> anything at all
+is cooking), subscribe to the <a
+href="contact.html#list_yadex"><code>yadex</code></a> mailing
+list.
+
+</p><hr>AYM $SELF_DATE
+
+</body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/docsrc/legal.html	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,69 @@
+<html>
+<head>
+<title>Legal</title>
+</head>
+<body>
+
+<div align="center">
+<img src="logo_small.png" alt="Fancy logo">
+<br>Yadex $VERSION ($SOURCE_DATE)
+<h1>Legal notices</h1>
+<table><tr><td></td><td width="50%" align="center">
+Definitely my favourite.
+<td></td></table>
+</div>
+<br>
+<br>
+<br>
+
+		<h2>Legal notice for Yadex</h2>
+
+<p>Yadex is GPL'd libre software. It incorporates code from DEU
+5.21 that was put in the public domain in 1994 by Raphaël Quinet
+and Brendon Wyber. The rest is Copyright © 1997-2000 André
+Majorel.
+
+<p>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.
+
+<p>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.
+
+<p> You should have received a copy of the <a href="COPYING">GNU
+General Public License</a> along with this program; if not,
+write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.
+
+		<h2>Legal notice for Atclib</h2>
+
+<p>Atclib is Copyright © 1995-1998 André Majorel.
+
+<p>This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public
+License as published by the Free Software Foundation; either
+version 2 of the License, or (at your option) any later version.
+
+<p>This library 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 <a href="COPYING.LIB">GNU Library General Public
+License</a> for more details.
+
+<p>You should have received a copy of the GNU Library General
+Public License along with this library; if not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+Boston, MA 02111-1307, USA.
+
+
+		<h2>Trademarks</h2>
+
+<p>All trademarks are the propriety of their owners.
+
+<p><hr>AYM $SELF_DATE
+
+</body>
+</html>
Binary file docsrc/logo.png has changed
Binary file docsrc/logo_small.png has changed
Binary file docsrc/mirror0.png has changed
Binary file docsrc/mirrorh.png has changed
Binary file docsrc/mirrorv.png has changed
Binary file docsrc/nook1.png has changed
Binary file docsrc/nook2.png has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/docsrc/packagers_guide.html	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,79 @@
+<html>
+  <head>
+    <title>Yadex packager's guide</title>
+  </head>
+  <body>
+    <div align="center">
+      <img src="logo_small.png" alt="Fancy logo">
+      <br>Yadex $VERSION ($SOURCE_DATE)
+      <h1>Packager's guide</h1>
+      <table>
+        <tr>
+	  <td>
+	  </td>
+	  <td width="50%" align="center">
+	    This is for people who plan to package Yadex.
+	  </td>
+	  <td>
+	  </td>
+	</tr>
+      </table>
+    </div>
+
+    <br>
+    <br>
+    <br>
+
+    <p>So you want to package Yadex&nbsp;? Here is a list of things you should
+      probably know&nbsp;:</p>
+
+    <p>
+      <ul>
+	<p><li>To make it install in <code>/usr</code> instead of
+	  <code>/usr/local</code>, re-run <code>configure</code> with the right
+	  <code>--prefix</code> option, type <code>make clean &amp;&amp; make
+	  all</code>. That's all there is to it.</p>
+	  
+	  <p>You shouldn't have to make any manual changes&nbsp;; most
+	  references to the prefix in the documentation and elsewhere use the
+	  files generated by <code>configure</code> (you'll have to <code>make
+	  clean</code>, however). One possibly undesirable consequence of this
+	  is that the doc from your package and the doc that one would get
+	  after installing from the source will not be identical. I suppose it
+	  doesn't matter.</p>
+
+	<p><li>From version 1.6 on, alternative prefixes are better supported
+	  but the behaviour has changed somewhat. Instead of looking for files
+	  in both <code>/usr</code> and <code>/usr/local</code>, Yadex uses
+	  only the prefix directory. The goal was to reduce the unwanted
+	  interactions between Yadexes installed with different prefixes on the
+	  same system. Since packagers typically use <code>/usr</code>, users
+	  should be able to have on their system both the original and the
+	  packaged version of Yadex. (Incidentally, that's not true for
+	  <code>/etc/yadex/$VERSION/yadex.cfg</code> but the FHS is to
+	  blame).</p> 
+
+	<p><li>To allow one to have several different versions installed at the
+	  same time on the same system, Yadex uses a somewhat unusual scheme
+	  where each file installed has the version number somewhere in its
+	  pathname. If your packaging system allows version <i>n</i> + 1 to
+	  have a different set of files than version <i>n</i> of the same
+	  package, this should cause no problem. In fact, if the package
+	  manager allows that, two different versions of the package could
+	  coexist (except that they would overwrite each other's symlinks in
+	  <code>bin/</code> and <code>man/</code>, but that's what they're
+	  for).
+
+	  <p>If you have problems with that scheme, let me know.</p>
+
+	<p><li>If you actually try to understand the makefile, you're going to
+	  end up hating me.</p> 
+
+      </ul>
+    </p>
+
+    <p><hr>AYM $SELF_DATE</p>
+
+  </body>
+</html>
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/docsrc/palette.html	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,84 @@
+<html>
+<head>
+<title>Yadex palette viewer</title>
+</head>
+<body>
+
+<div align="center">
+<img src="logo_small.png" alt="Fancy logo">
+<br>Yadex $VERSION ($SOURCE_DATE)
+<h1>Palette viewer</h1>
+</div>
+<br>
+<br>
+<br>
+
+	<h2>What's it for</h2>
+
+<p>The palette viewer is for people who do graphics hacking and
+want to know the exact details of how the game colour system
+(<code>PLAYPAL</code> and <code>COLORMAP</code>) works. It lets
+you know, for example&nbsp;:
+
+<ul>
+<li>how colour numbers are mapped to RGB values,
+<li>how colours change with brightness,
+<li>how many colour numbers are mapped to by a given colour number,
+<li>how many colour numbers a given colour number maps to.
+</ul>
+
+	<h2>Key bindings</h2>
+
+<dl>
+<dt>[<kbd>Left</kbd>]
+<br>[<kbd>Right</kbd>]
+<br>[<kbd>Up</kbd>]
+<br>[<kbd>Down</kbd>]
+<dd>Move cursor in that direction.
+
+<dt>[<kbd>Home</kbd>]
+<br>[<kbd>0</kbd>]
+<br>[<kbd>^</kbd>]
+<dd>Move cursor to beginning of current line.
+
+<dt>[<kbd>End</kbd>]
+<br>[<kbd>$</kbd>]
+<dd>Move cursor to end of current line.
+
+<dt>[<kbd>Return</kbd>]
+<dd>Move cursor to beginning of next line.
+
+<dt>[<kbd>G</kbd>]
+<br>[<kbd>L</kbd>]
+<dd>Move cursor to beginning of last line.
+
+<dt>[<kbd>H</kbd>]
+<dd>Move cursor to beginning of first line.
+
+<dt>[<kbd>M</kbd>]
+<dd>Move cursor to beginning of middle line.
+
+<dt>[<kbd>Pgup</kbd>]
+<dd>Previous <code>COLORMAP</code> entry.
+
+<dt>[<kbd>Pgdn</kbd>]
+<dd>Next <code>COLORMAP</code> entry.
+
+<dt>[<kbd>m</kbd>]
+<dd>Toggle <code>COLORMAP</code> mapping.
+
+<dt>[<kbd>+</kbd>]
+<br>[<kbd>=</kbd>]
+<dd>Rotate palette left.
+
+<dt>[<kbd>-</kbd>]
+<dd>Rotate palette right.
+
+<dt>[<kbd>Esc</kbd>]
+<dd>Exit the palette viewer
+
+</dl>
+
+<p><hr>AYM $SELF_DATE
+</body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/docsrc/reporting.html	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,44 @@
+<html>
+<head>
+<title>Reporting bugs</title>
+</head>
+<body>
+
+<div align="center">
+<img src="logo_small.png" alt="Fancy logo">
+<br>Yadex $VERSION ($SOURCE_DATE)
+<h1>Reporting bugs</h1>
+</div>
+<br>
+<br>
+<br>
+
+<p>If you find a bug, tell the <a
+href="contact.html#list_yadex">list</a> about it. It's
+important. Especially if it makes Yadex crash or lose data.
+However, there are a few things to bear in mind&nbsp;:
+
+<ul>
+<li>Some bugs are already known (cf. <a
+href="TODO"><code>TODO</code></a>). You don't need to spend time
+reporting them because I'm already aware of them.
+
+<br><br><li>A vague report like "it has crashed" is nearly
+useless. If you want me to fix the bug, you need to be specific.
+What's your hardware and software configuration&nbsp;? What
+version of Yadex do you run&nbsp;? What iwad and pwads do you
+use&nbsp;? What exactly did you do&nbsp;? What message did you
+get exactly&nbsp;? I know that collecting all that information
+can be time consuming but there's no way around it. Consider
+including the output of "<code>make showconf</code>".
+
+<br><br><li>Some bugs don't come from programming errors but
+from flaws in the design. So they can't be fixed, unless I
+redesign and rewrite a significant portion of the program.
+
+</ul>
+
+<p><hr>AYM $SELF_DATE
+
+</body>
+</html>
Binary file docsrc/slice1.png has changed
Binary file docsrc/slice2.png has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/docsrc/tips.html	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,53 @@
+<html>
+<head>
+<title>Tips</title>
+</head>
+<body>
+
+<div align="center">
+<img src="logo_small.png" alt="Fancy logo">
+<br>Yadex $VERSION ($SOURCE_DATE)
+<h1>Tips</h1>
+</div>
+<br>
+<br>
+<br>
+
+	<h2>Running Yadex remotely</h2>
+
+<p>Like any non-SHM X application, Yadex can be run remotely. That is, the
+machine on which Yadex runs and the machine that Yadex uses for its display do
+not have to be the same. For example, from Unix box <code>mine</code> on your
+desk, you can telnet into Unix box <code>hers</code> in another room and run
+Yadex from there, but have it display on <code>mine</code>.
+
+<pre>mine$ <b>xhost hers</b>
+hers$ <b>DISPLAY=mine:0 yadex</b></pre>
+
+	<h2>Having several versions of Yadex installed simultaneously</h2>
+
+<p>Starting with version 1.3.0, it should be easier to have several versions
+of Yadex installed at once. When you install Yadex <b>x.y.z</b>, the following
+files are created&nbsp;:
+
+<ul>
+  <li><code>/usr/local/bin/yadex-<b>x.y.z</b></code>
+  <li><code>/usr/local/share/games/yadex/<b>x.y.z</b>/*.ygd</code>
+  <li><code>/etc/yadex/<b>x.y.z</b>/yadex.cfg</code>
+  <li><code>/usr/local/man/man6/yadex-<b>x.y.z.</b>.6</code>
+</ul>
+
+All these files have the version number somewhere in their name. Therefore,
+when you install a new version, the previous version(s) is/are not clobbered.
+
+<p>In addition, the installation creates <code>/usr/local/bin/yadex</code> as a
+symlink to <code>/usr/local/bin/yadex-x.y.z</code>, so that you can still
+invoke Yadex by typing just "<code>yadex</code>". To invoke older versions,
+type the long name ("<code>yadex-x.y.z</code>").
+
+<p>Same thing for the man page.
+
+</p><hr>AYM $SELF_DATE
+
+</body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/docsrc/trivia.html	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,32 @@
+<html>
+<head>
+<title>Trivia</title>
+</head>
+<body>
+
+<div align="center">
+<img src="logo_small.png" alt="Fancy logo">
+<br>Yadex $VERSION ($SOURCE_DATE)
+<h1>Trivia</h1>
+</div>
+<br>
+<br>
+<br>
+
+	<h2>What's in a name ?</h2>
+
+<p>In its previous incarnation, Yadex was named <em>Yade</em>,
+which means Yet Another Doom Editor. I later realized that this
+name was already taken (by Yet Another Diagram Editor). I
+decided that the easiest way to remedy this would be to append a
+fifth letter. I chose "<em>x</em>" because it has a neat regular
+shape and because it evokes both Unix and X and therefore
+conveys an important political message <tt>;-)</tt>.
+
+<p>The right way to typeset it is with a capital Y and the rest
+in lower case. Think of it as of a proper noun.
+
+<p><hr>AYM $SELF_DATE
+
+</body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/docsrc/trouble.html	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,158 @@
+<html>
+<head>
+<title>Troubleshooting</title>
+</head>
+<body>
+
+<div align="center">
+<img src="logo_small.png" alt="Fancy logo">
+<br>Yadex $VERSION ($SOURCE_DATE)
+<h1>Troubleshooting</h1>
+</div>
+<br>
+<br>
+<br>
+
+	<h2>While compiling</h2>
+
+<dl>
+  <dt>
+    <strong>Compilation fails (errors during "<code>make</code>")</strong>
+
+  <dd>The most common causes are &nbsp;:
+    <dl>
+      <br>
+      <dt>You don't have GNU make.
+      <dd>If you type "<code>make&nbsp;--version</code>", you should see
+	something that starts with
+	"<code>GNU&nbsp;Make&nbsp;version&nbsp;something</code>".  Otherwise,
+	you don't have GNU make. Installing GNU make is not very difficult.
+	Fetch the archive <code>make-<var>version</var>.tar.gz</code> from
+	<code>ftp.gnu.org</code>, extract its contents, type
+	"<code>./configure; make; su -c 'make install'</code>" and you're set.
+	Don't worry, this is not going to overwrite your old make program. The
+	new make program is installed as <code>/usr/bin/local/make</code>. Use
+	that to compile and install Yadex.
+
+      <br>
+      <br>
+      <dt>"<code>cc/c++: command not found</code>"
+      <dd>You don't have a C or C++ compiler. You could install EGCS or GCC
+        (they're free).
+
+      <br>
+      <br>
+      <dt>"<code>-lX11</code>: no such file or directory"
+      <dd>The linker can't find the X11 libraries.  Make sure that you
+	have one or more files named "<code>libX11*</code>" on your system and
+	that they are in <code>/usr/X11R6/lib</code>. If they're somewhere
+	else, try typing "<code>make&nbsp;X11LIBDIR=/somewhere/else</code>"
+	instead.
+
+      <br>
+      <br>
+      <dt>"<code>no space left on device</code>".
+      <dd>Your disk is full :-).
+
+      <br>
+      <br>
+      <dt>Something else
+      <dd>Mail me the output of "<code>make showconf</code>", the command you
+        ran and the error messages you got.
+    </dl>
+</dl>
+
+	<h2>While installing</h2>
+
+<dl>
+  <dt><strong>Installation fails (errors during
+  "<code>make&nbsp;install</code>")</strong>
+
+  <dd>The most common causes are&nbsp;:
+    <dl>
+      <br>
+      <dt>"<code>permission denied</code>".
+      <dd>You don't have the necessary rights to copy the files to the
+	installation directories. Either try logging in as <code>root</code>
+	and running "<code>make install</code>" again or specifying another
+	target directory.
+
+      <br>
+      <br>
+      <dt>"<code>no space left on device</code>".
+      <dd>Your disk is full :-).
+      
+      <br>
+      <br>
+      <dt>Something else
+      <dd>Mail me the output of "<code>make showconf</code>", the command you
+        ran and the error messages you got.
+    </dl>
+</dl>
+
+	<h2>While running</h2>
+
+<dl>
+  <dt>
+    <strong>Error message "<code>Can't open ".../doom2.wad" (No such file or
+    directory)</code>"</strong>
+
+  <dd>
+    Yadex can't find your Doom II iwad. Either&nbsp;:
+    <ul>
+      <li>
+	copy it or symlink it to
+	<code>/usr/local/share/games/doom2/doom2.wad</code> or
+      <li>
+	change the <code>iwad2=</code> parameter in
+	<code>/usr/local/etc/yadex.cfg</code>.
+    </ul>
+
+  <br>
+  <dt>
+    <strong>Error message "<code>invalid option: "-something"</code>"</strong>
+
+  <dd>
+    Yadex wants a space between options and their argument. For example,
+    "<code>yadex&nbsp;-g&nbsp;doom</code>" is okay,
+    "<code>yadex&nbsp;-gdoom</code>" isn't.
+
+  <br>
+  <br>
+  <dt>
+    <strong>The display lags behind when I drag objects or scroll</strong>
+
+  <dd>
+    Yes. Yadex takes too much time to redraw its window. This kill be fixed in
+    another release. In the meantime, you can try to&nbsp;:
+    <ul>
+      <li>run Yadex with the <code>-P</code> option (but you'll get more
+	flicker),
+      <li>use a smaller window&nbsp;,
+      <li>use a lesser screen depth, such as 8 BPP,
+      <li>keep the grid step large or disable the grid completely,
+      <li>use more powerful hardware.
+    </ul>
+
+  <br>
+  <dt><strong>The window has turned black&nbsp;!</strong>
+
+  <dd>Don't panic. This is a known bug, and a totally harmless
+    one. Yadex is not crashed or hung. It just didn't realize that its window
+    has been erased and needs to be redrawn. It still accepts input, though the
+    display might look funny. If that disturbs you, you can back out by
+    pressing [<kbd>Esc</kbd>], several times if necessary, and everything will
+    return to normal.
+
+</dl>
+
+<p>If your problem is not listed here, you might have found a
+bug. Read on how to report bugs <a
+href="reporting.html">there</a>.
+
+<p>If the suggested remedies don't fix your problem, see <a
+href="help.html">there</a> how to get help.
+
+<p><hr>AYM $SELF_DATE
+</body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/docsrc/users_guide.html	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,2507 @@
+<html>
+<head>
+<title>Yadex user's guide</title>
+<meta http-equiv="Content-Style-Type" content="text/css">
+<style type="text/css">
+  DT {
+    margin-bottom:       1em;
+    margin-top:          1em;
+    display:             list-item;
+    list-style-image:    none;
+    list-style-position: inside;
+    list-style-type:     disc;
+  }
+  DD {
+    margin-bottom: 1em;
+    margin-top:    1em
+  }
+</style>
+</head>
+<body>
+
+<div align="center">
+  <img src="logo_small.png" alt="Fancy logo">
+  <br>Yadex $VERSION ($SOURCE_DATE)
+  <h1>User's guide</h1>
+  <table>
+    <tr>
+      <td>
+      </td>
+      <td width="50%" align="center">
+	<strong>
+	  Warning : this document is unfinished, ill-structured and
+	  incomplete.
+	</strong>
+      </td>
+      <td>
+      </td>
+    </tr>
+  </table>
+</div>
+<br>
+<br>
+<br>
+
+<p>Contents :
+
+<p>
+<!-- generated by htmltoc { -->
+  <ul>
+    <li><a href="#toc-1">1. Introduction</a></li>
+    <ul>
+      <li><a href="#toc-1-1">1.1. Yadex in one paragraph</a></li>
+      <li><a href="#toc-1-2">1.2. What do I need ?</a></li>
+      <ul>
+        <li><a href="#toc-1-2-1">1.2.1. Iwad</a></li>
+        <li><a href="#toc-1-2-2">1.2.2. Directories</a></li>
+        <li><a href="#toc-1-2-3">1.2.3. Display</a></li>
+      </ul>
+      <li><a href="#toc-1-3">1.3. Compiling and installing Yadex</a></li>
+    </ul>
+    <li><a href="#toc-2">2. Running Yadex</a></li>
+    <ul>
+      <li><a href="#toc-2-1">2.1. The command line arguments</a></li>
+      <li><a href="#opt">2.2. Options</a></li>
+      <li><a href="#game">2.3. Specifying the game for which
+		you want to edit</a></li>
+      <li><a href="#pwads">2.4. Specifying the names of
+		pwads to load</a></li>
+      <li><a href="#env">2.5. Environment variables</a></li>
+    </ul>
+    <li><a href="#toc-3">3. Editing levels with Yadex</a></li>
+    <ul>
+      <li><a href="#toc-3-1">3.1. Using external textures, flats, etc.</a></li>
+      <li><a href="#toc-3-2">3.2. Logging of time spent</a></li>
+      <li><a href="#toc-3-3">3.3. The prompt commands</a></li>
+      <li><a href="#toc-3-4">3.4. Moving around</a></li>
+      <ul>
+        <li><a href="#toc-3-4-1">3.4.1. Moving the pointer</a></li>
+        <li><a href="#toc-3-4-2">3.4.2. Scrolling</a></li>
+        <li><a href="#toc-3-4-3">3.4.3. Autoscrolling</a></li>
+        <li><a href="#toc-3-4-4">3.4.4. Jumping</a></li>
+      </ul>
+      <li><a href="#toc-3-5">3.5. Zooming in and out</a></li>
+      <li><a href="#toc-3-6">3.6. The grid</a></li>
+      <li><a href="#toc-3-7">3.7. Inserting objects</a></li>
+      <li><a href="#toc-3-8">3.8. Copying objects</a></li>
+      <li><a href="#toc-3-9">3.9. Deleting objects</a></li>
+      <li><a href="#toc-3-10">3.10. Changing the properties of objects</a></li>
+      <li><a href="#toc-3-11">3.11. Moving objects a.k.a. drag-and-drop</a></li>
+      <li><a href="#toc-3-12">3.12. Renumbering objects</a></li>
+      <ul>
+        <li><a href="#toc-3-12-1">3.12.1. Exchanging objects numbers</a></li>
+      </ul>
+      <li><a href="#toc-3-13">3.13. Selecting objects</a></li>
+      <li><a href="#toc-3-14">3.14. The use of [<kbd>Shift</kbd>]</a></li>
+      <li><a href="#toc-3-15">3.15. Sector miscellaneous operations</a></li>
+      <li><a href="#toc-3-16">3.16. Thing miscellaneous operations</a></li>
+      <li><a href="#toc-3-17">3.17. Setting/toggling/clearing thing flags</a></li>
+      <li><a href="#toc-3-18">3.18. Vertex miscellaneous operations</a></li>
+      <li><a href="#toc-3-19">3.19. Linedef miscellaneous operations</a></li>
+      <li><a href="#toc-3-20">3.20. Setting/toggling/clearing linedef flags</a></li>
+      <li><a href="#toc-3-21">3.21. Undoing</a></li>
+      <li><a href="#toc-3-22">3.22. Cut-and-paste from one level to another</a></li>
+      <li><a href="#toc-3-23">3.23. Using the flat/patch/sprite/texture viewer</a></li>
+      <li><a href="#toc-3-24">3.24. Saving</a></li>
+      <li><a href="#toc-3-25">3.25. Closing a window</a></li>
+    </ul>
+    <li><a href="#toc-4">4. Variables and configuration</a></li>
+    <ul>
+      <li><a href="#toc-4-1">4.1. Variables</a></li>
+      <ul>
+        <li><a href="#toc-4-1-1">4.1.1. The font</a></li>
+        <li><a href="#toc-4-1-2">4.1.2. Mouse wheel and other mouse issues</a></li>
+      </ul>
+      <li><a href="#toc-4-2">4.2. Preferences</a></li>
+      <li><a href="#toc-4-3">4.3. Command line</a></li>
+      <li><a href="#toc-4-4">4.4. Environment variables</a></li>
+      <li><a href="#toc-4-5">4.5. Configuration files</a></li>
+      <ul>
+        <li><a href="#toc-4-5-1">4.5.1. Contents of configuration files</a></li>
+        <li><a href="#config_locate">4.5.2. Locating
+			configuration files</a></li>
+        <li><a href="#toc-4-5-3">4.5.3. Default configuration files</a></li>
+        <li><a href="#toc-4-5-4">4.5.4. User-specified configuration files</a></li>
+        <li><a href="#toc-4-5-5">4.5.5. Organising your configuration files</a></li>
+      </ul>
+    </ul>
+    <li><a href="#toc-5">5. Game definition files</a></li>
+    <ul>
+      <li><a href="#toc-5-1">5.1. Contents of game definition files</a></li>
+      <li><a href="#ygd_locate">5.2. Locating game definition
+		files</a></li>
+      <li><a href="#toc-5-3">5.3. Use of game definition files</a></li>
+    </ul>
+    <li><a href="#toc-6">6. Known bugs</a></li>
+    <li><a href="#games">7. Supported games</a></li>
+    <ul>
+      <li><a href="#toc-7-1">7.1. Doom</a></li>
+      <li><a href="#toc-7-2">7.2. Doom II</a></li>
+      <li><a href="#toc-7-3">7.3. Doom alpha</a></li>
+      <li><a href="#toc-7-4">7.4. Doom press release pre-beta</a></li>
+      <li><a href="#toc-7-5">7.5. Final Doom</a></li>
+      <li><a href="#toc-7-6">7.6. Heretic</a></li>
+      <li><a href="#toc-7-7">7.7. Hexen</a></li>
+      <li><a href="#toc-7-8">7.8. Strife</a></li>
+      <li><a href="#toc-7-9">7.9. Ultimate Doom</a></li>
+      <li><a href="#toc-7-10">7.10. Boom</a></li>
+      <li><a href="#toc-7-11">7.11. EDGE</a></li>
+      <li><a href="#toc-7-12">7.12. MBF</a></li>
+      <li><a href="#toc-7-13">7.13. Other derivatives</a></li>
+    </ul>
+  </ul>
+<!-- } generated by htmltoc -->
+</p>
+
+	<hr noshade>
+	<h2><a name="toc-1">1. Introduction</a></h2>
+
+		<h3><a name="toc-1-1">1.1. Yadex in one paragraph</a></h3>
+
+<p>Yadex is a Doom level (wad) editor for Unix systems running
+X, including Linux. It supports Doom, Doom II, Ultimate Doom,
+Final Doom, Heretic, Doom press release pre-beta and also, in a
+more or less limited way, Hexen, Strife and Doom alpha. It is
+available under the terms of the GPL.
+
+		<h3><a name="toc-1-2">1.2. What do I need ?</a></h3>
+
+<p>To compile, install and run this release of Yadex, you need
+
+<ul>
+  <li>a POSIX-compatible environment (such as Unix),
+  <li>a C compiler (ISO-compatible),
+  <li>a C++ compiler (ISO-compatible),
+  <li>GNU make (it won't work with other flavours of make),
+  <li>an HTML viewer to read the doc,
+  <li>a Doom/Doom II/Heretic/Hexen/Strife iwad,
+  <li>X11R6 or X11R5.
+</ul>
+
+<p>More specifically, Yadex expects that
+
+<ul>
+  <li>the routines in <code>ctype.h</code> accept the range
+    <code>CHAR_MIN</code> through <code>UCHAR_MAX</code>,
+
+  <li>the C library supports <code>hypot()</code> and at least
+    one of <code>nanosleep()</code> and <code>usleep()</code>.
+</ul>
+
+		<h4><a name="toc-1-2-1">1.2.1. Iwad</a></h4>
+
+<p>A shareware Doom or Heretic iwad or a demo Hexen or Strife
+iwad is okay but you need a registered iwad if you want to be
+able to save your changes.
+
+		<h4><a name="toc-1-2-2">1.2.2. Directories</a></h4>
+
+<p>Yadex mostly conforms to the <a
+href="http://www.pathname.com/fhs/"> FHS (filesystem hierarchy
+standard)</a>. By default, the installation procedure will try
+to copy files in the following directories, creating the
+directories if they don't exist&nbsp;;
+
+<ul>
+<li><code>/usr/local/bin</code>
+<li><code>/etc/yadex/$VERSION</code>
+<li><code>/usr/local/man/man6</code>
+<li><code>/usr/local/share/games/yadex/$VERSION</code>
+</ul>
+
+<p>So make sure you have the necessary rights before installing.
+If you don't, install in a different directory by running
+<code>./configure</code> with the <code>--prefix</code> option.
+
+		<h4><a name="toc-1-2-3">1.2.3. Display</a></h4>
+
+<p>Yadex uses about 270 different colours. In most cases, on
+PseudoColor displays, there aren't that many free colour cells.
+So, if it detects a PseudoColor display, Yadex uses a private
+colormap so as to get as many free colour cells as possible.
+The drawback of this method is that, when you're in the Yadex
+window, all other windows are displayed with wrong colours and
+vice-versa.
+
+<p>What's more, as PseudoColor displays typically have 256
+colours (at least on PC), which is less than the number of
+colours needed, Yadex might have to assign the same physical
+colour to different logical colours. If it happens, it will try
+to render the colours of the game accurately at the expense of
+the application colours.
+
+<p>Executive summary: if you can, use a TrueColor or DirectColor
+display and a depth of more than 8 bits per pixel (E.G. by
+launching X with "<code>startx -- -bpp 16</code>").
+
+<p>A 640x480 screen is okay though, of course, a larger display
+is better.
+
+	<h3><a name="toc-1-3">1.3. Compiling and installing Yadex</a></h3>
+
+See <a href="README"><code>README</code></a>.
+
+<p>Don't forget to tell Yadex where your iwads are by changing
+the lines "<code>iwad1&nbsp;=</code>",
+"<code>iwad2&nbsp;=</code>" etc. in
+<code>/etc/yadex/$VERSION/yadex.cfg</code>.
+If there is an iwad you don't have, you can just comment out the
+corresponding line.
+
+	<hr noshade>
+	<h2><a name="toc-2">2. Running Yadex</a></h2>
+
+		<h3><a name="toc-2-1">2.1. The command line arguments</a></h3>
+
+<p>Yadex takes two sorts of command line arguments&nbsp;:
+parameters and options. An option is a command line argument
+that starts with a "<code>-</code>".
+
+<p>Some options take an argument. The argument must be
+separated from the option by some whitespace.
+<strong>Constructs like "<code>-othingy</code>" are not
+recognized. You have to type "<code>-o thingy</code>".</strong>
+
+<p>The "<code>-file</code>" option takes a variable number of
+arguments. It uses all the non-options up to the next option.
+
+<p>The options that take no argument can be negated by using a
+"<code>+</code>" instead of a "<code>-</code>". For example,
+"<code>+sb</code>" will undo the effect of a
+"<code>swap_buttons&nbsp;=&nbsp;true</code>" directive in the
+config file.
+
+<p>In general, if you specify the same option more than once,
+the last occurrence overrides the previous ones. For example,
+"<code>yadex&nbsp;+P&nbsp;-P</code>" is equivalent to
+"<code>yadex&nbsp;-P</code>". Similarly,
+"<code>yadex&nbsp;-i1&nbsp;foo.wad&nbsp;-i1&nbsp;bar.wad&nbsp;-i1&nbsp;baz.wad</code>"
+boils down to "<code>yadex&nbsp;-i1&nbsp;baz.wad</code>".
+
+<p>The "<code>-pwad</code>" (or "<code>-pw</code>") option,
+however are additive. Each occurrence will add to the previous
+ones. For instance,
+"<code>yadex&nbsp;-pwad&nbsp;foo.wad&nbsp;-pwad&nbsp;bar.wad</code>"
+is equivalent to "<code>yadex&nbsp;foo.wad&nbsp;bar.wad</code>".
+
+<p>Any command line argument that is not an option is treated as
+the name of a pwad to load. You can put as many names of pwads
+on the command line as you wish (or none at all). The details
+of specifying pwad names are discussed <a
+href="#pwads">there</a>.
+
+		<h3>2.2. <a name="opt">Options</a></h3>
+
+<p>To know about the command line options that Yadex
+understands, type
+
+<p><code>$ yadex --help</code>
+
+<p>You'll get this:
+
+<pre>
+-b                 <var>string</var>     Run benchmark and exit successfully
+-f  -config_file   <var>string</var>     Config file
+-d  -debug                    Debug mode
+    -expert                   Expert mode
+-fc -fake_cursor              Fake cursor
+-fn -font          <var>string</var>     Font name
+-g  -game          <var>string</var>     Game
+-h  -height        <var>integer</var>    Initial window height
+-?  -help  --help             Show usage summary
+-i1 -iwad1         <var>string</var>     The name of Doom iwad
+-i2 -iwad2         <var>string</var>     The name of the Doom II iwad
+-i3 -iwad3         <var>string</var>     The name of the Heretic iwad
+-i4 -iwad4         <var>string</var>     The name of the Hexen iwad
+-i5 -iwad5         <var>string</var>     The name of the Strife iwad
+-i6 -iwad6         <var>string</var>     The name of the Doom alpha 0.2 iwad
+-i7 -iwad7         <var>string</var>     The name of the Doom alpha 0.4 iwad
+-i8 -iwad8         <var>string</var>     The name of the Doom alpha 0.5 iwad
+-i9 -iwad9         <var>string</var>     The name of the Doom press release iwad
+-i10 -iwad10       <var>string</var>     The name of the Strife 1.0 iwad
+-pw -pwad          <var>string</var>     Pwad file to load
+-P  -no_pixmap                No pixmap, saves memory, more flicker
+-q  -quiet                    Quiet mode
+-qq -quieter                  Quieter mode
+-s0 -select0                  Automatic selection of 0th object
+-sb -swap_buttons             Swap mouse buttons
+-td -text_dot                 DrawScreenText debug flag
+-v  -verbose                  Verbose mode
+    --version                 Print version and exit
+-w  -width         <var>integer</var>    Initial window width
+-z  -zoom          <var>integer</var>    Initial zoom factor
+</pre>
+
+<p>You might wonder what the "<code>-file</code>",
+"<code>-pw</code>" and "<code>-pwad</code>" options are for
+since it's so simple to just put the names of the pwads on the
+command line. The answer is that they're only here for
+compatibility with previous versions of Yadex/Yade/DEU. Don't
+use them. They might go away one day.
+
+		<h3>2.3. <a name="game">Specifying the game for which
+		you want to edit</a></h3>
+
+<p>Yadex can handle several games (Doom, Doom II, Heretic, etc.)
+but only one at a time. Unfortunately, that game can't be
+changed dynamically. If you want to switch game, you must quit
+Yadex and run it again.
+
+<p>By default, the game used is the one specified by the
+"<code>game=</code>" directive in the configuration file. If
+you want to override the default, use "<code>-g
+<var>game</var></code>".
+
+<p>The allowed values for <code><var>game</var></code> are&nbsp;:
+<dl>
+  <dt>"<code>doom</code>"
+  <dd>Doom and Ultimate Doom (shareware or registered)
+
+  <dt>"<code>doom02</code>"
+  <dd>Doom alpha 0.2
+
+  <dt>"<code>doom04</code>"
+  <dd>Doom alpha 0.4
+
+  <dt>"<code>doom05</code>"
+  <dd>Doom alpha 0.5
+
+  <dt>"<code>doom2</code>"
+  <dd>Doom II and Final Doom
+
+  <dt>"<code>doompr</code>"
+  <dd>Doom press release pre-beta
+
+  <dt>"<code>heretic</code>"
+  <dd>Heretic (shareware or registered)
+
+  <dt>"<code>hexen</code>"
+  <dd>Hexen (demo or commercial)
+
+  <dt>"<code>strife</code>"
+  <dd>Strife 1.1 or later (demo or commercial)
+
+  <dt>"<code>strife10</code>"
+  <dd>Strife 1.0 (demo or commercial)
+</dl>
+
+<p>Not all those games are fully supported. For details, see <a
+href="#games">there</a>.
+
+
+		<h3>2.4. <a name="pwads">Specifying the names of
+		pwads to load</a></h3>
+
+<p>When you have to specify the name of a pwad to load, for
+example in the <code>r</code> command, or as a command line
+argument, you don't always have to spell it all out.
+
+<ul>
+  <li>The <code>.wad</code> extension can be omitted, it will
+    be added automatically.  For example, specifying the name
+    "<code>foo</code>" is equivalent to specifying
+    "<code>foo.wad</code>".  An unfortunate consequence of this
+    convention is that it's impossible to load a wad that would
+    be really called "<code>foo</code>".  Though, under DOS, you
+    can still work around this limitation by specifying the name
+    with a trailing dot, ("<code>foo.</code>").
+
+  <li>
+    <p>
+      The path can sometimes be omitted too, if the wad is in
+      one of the <dfn>standard directories</dfn>, or one of
+      their subdirectories.  If no file of the name you
+      specified is found in the current directory, Yadex will
+      look for a file of that name in the standard directories,
+      which are&nbsp;:
+    </p>
+
+    <ol>
+      <li>your home directory,
+      <li><code>/usr/local/share/games/</code><var>game</var>,
+      <li><code>/usr/share/games/</code><var>game</var>,
+      <li><code>/usr/local/share/games/wads</code>,
+      <li><code>/usr/share/games/wads</code>,
+    </ol>
+
+    <p>(where <var>game</var> is the name of the <a
+    href="#game">game</a>).</p>
+
+    <p>On the other hand, if you give an absolute file name,
+    that is one that begins with a "<code>/</code>", the
+    standard directories will <em>not</em> be used. Yadex will
+    only try to open the file of the exact name you specified.
+
+    <p>For example, if you type "<code>yadex -g doom2
+    foo/bar</code>", Yadex will look for the following files in
+    order&nbsp;:</p>
+
+    <ol>
+      <li><code>~/foo/bar.wad</code>,
+      <li><code>/usr/local/share/games/doom2/foo/bar.wad</code>,
+      <li><code>/usr/share/games/doom2/foo/bar.wad</code>,
+      <li><code>/usr/local/share/games/wads/foo/bar.wad</code>,
+      <li><code>/usr/share/games/wads/foo/bar.wad</code>,
+    </ol>
+
+    <p>and open the first it finds.</p>
+
+    <p>But if you type
+    "<code>yadex&nbsp;-g&nbsp;doom2&nbsp;/foo/bar</code>" (note
+    the leading slash), Yadex will try to open
+    "<code>/foo/bar.wad</code>", period.
+
+    <p>The philosophy behind those standard directories is
+    that&nbsp;:
+
+    <ul>
+      <li>a local file overrides a global one,
+      <li>a game-specific file overrides a non-game-specific one.
+    </ul>
+</ul>
+
+<p>Gotcha: those shorthands can only be used when
+<em>reading</em> a pwad. When <em>writing</em> to a pwad, you
+always have to specify the exact name, with the full path and
+extension.
+
+		<h3>2.5. <a name="env">Environment variables</a></h3>
+
+<dl>
+  <dt><code>DOOMWADDIR</code>
+  <dd>No, <code>DOOMWADDIR</code> is <em>not</em> supported.
+    Perhaps in another version...
+
+  <dt><code>DISPLAY</code>
+  <dd>Unix only. The name of the X display that Yadex will try
+    to connect to.
+
+  <dt><code>HOME</code>
+  <dd>Used to expand <code>~</code> when locating configuration
+    and game definition files.
+
+  <dt><code>LINES</code>
+  <dd>If set, Yadex assumes the tty has that many lines instead
+    of 24. The value must be an unsigned, non-zero decimal
+    integer.
+
+  <dt><code>TMPDIR</code>
+  <dd>If set, swap files are created there. Otherwise, in
+    <code>/tmp</code>.
+
+  <dt><code>YADEX_GAME</code>
+  <dd>Indicates the game to use. Overrides the <code>game</code>
+    parameter in the config file, is overridden by the
+    <code>-g</code> command line option.
+</dl>
+
+	<hr noshade>
+	<h2><a name="toc-3">3. Editing levels with Yadex</a></h2>
+
+		<h3><a name="toc-3-1">3.1. Using external textures, flats, etc.</a></h3>
+
+<p>Like Doom, Yadex accepts the addition and replacement of
+resources from a pwad. In general, if the same resource is
+defined in several wads, the last definition is used. This is
+also true if the same resource is defined several times in the
+same wad. It's not recommended that you use lower case names in
+your wads; sometimes it's handled but sometimes it's not. So
+always use upper-case names.</p>
+
+<dl>
+  <dt>Flats
+  <dd>New or replacement flats are recognized iff they're placed
+    between <code>FF_START</code>/<code>F_END</code> or
+    <code>FF_START</code>/<code>FF_END</code> labels. There can
+    be any number of <code>FF_START</code>/<code>F_END</code>
+    and <code>FF_START</code>/<code>FF_END</code> pairs and they
+    don't have to be in the same pwad. If there are several
+    lumps for the same flat, the last one is used.
+
+  <dt>Palette
+  <dd>If there is a replacement <code>PLAYPAL</code> lump, it's
+    used. If there are several <code>PLAYPAL</code> lumps, the
+    last one is used.
+
+  <dt>Patches
+  <dd>New or replacement patches are recognized iff they're
+    between <code>P_START</code> and <code>P_END</code> or
+    <code>PP_START</code> and <code>PP_END</code>. Within a
+    group of patches, labels <code>P1_START</code>,
+    <code>P1_END</code>, <code>P2_START</code>,
+    <code>P2_END</code>, <code>P3_START</code> and
+    <code>P3_END</code> are ignored&nbsp;; any other label
+    elicits a warning. New patches must also appear in the
+    <code>PNAMES</code> lump or the texture browser won't be
+    able to use them. If there are several <code>PNAMES</code>
+    lumps, the last one is used. If there are several lumps for
+    the same flat, the last one is used.
+
+  <dt>Sprites
+  <dd>New or replacement sprites are recognized iff they're
+    between one of the following pair of labels&nbsp;:
+    <code>S_START</code>/<code>S_END</code>,
+    <code>SS_START</code>/<code>S_END</code> or
+    <code>SS_START</code>/<code>SS_END</code>. There can be any
+    number of label pairs and they don't have to be in the same
+    pwad. If there are several lumps for the same sprite, the
+    last one is used.
+
+  <dt>Textures
+  <dd>New or replacement textures are recognized iff they're in
+    a <code>TEXTURE1</code> or <code>TEXTURE2</code> lump. If
+    the same texture happens to be defined in both
+    <code>TEXTURE1</code> and <code>TEXTURE2</code> (which
+    should not happen), only the definition in
+    <code>TEXTURE1</code> is used. If there are several
+    <code>TEXTURE1</code> lumps, the last one is used. If there
+    are several <code>TEXTURE2</code> lumps, the last one is
+    used. If it exists, <code>TEXTURE2</code> is always
+    susceptible to be used, even for games where it's not
+    supposed to exist, like Doom&nbsp;II.
+</dl>
+
+		<h3><a name="toc-3-2">3.2. Logging of time spent</a></h3>
+
+<p>If you edit a level from a file and there exists a file in
+the same directory with the same name but with the extension
+<code>.yl</code>, that file will be used to keep track of the
+time you spent editing that level. At the end of the editing
+session, Yadex will append a line to the <code>.yl</code> file
+with the name of the level and the number of minutes spent on
+it.
+
+<p> Note that if the <code>.yl</code> file does not already
+exist, it is <em>not</em> created. This is to prevent the
+creation of a large number of small useless files when browsing
+through a collection of wads. Thus, if you want to enable
+logging, you need to manually create the log file first with a
+command such as "<code>touch <var>name</var>.yl</code>".
+
+		<h3><a name="toc-3-3">3.3. The prompt commands</a></h3>
+
+<p>You can get a summary of the prompt commands
+by typing "<code>?</code>" at the Yadex prompt.
+
+		<h3><a name="toc-3-4">3.4. Moving around</a></h3>
+
+			<h4><a name="toc-3-4-1">3.4.1. Moving the pointer</a></h4>
+
+<p>In the X11 version, the only way to do that is to
+move the pointer device (i.e. the mouse).
+
+			<h4><a name="toc-3-4-2">3.4.2. Scrolling</a></h4>
+
+<p>The arrow keys [<kbd>Left</kbd>], [<kbd>Right</kbd>],
+[<kbd>Up</kbd>] and [<kbd>Down</kbd>] scroll a little at a time,
+by default 10% of the screen/window width or height. You can
+change the exact amount by setting the variable
+<code>scroll_less</code> in the configuration file.
+
+<p>[<kbd>Page-up</kbd>], [<kbd>Page-down</kbd>],
+[<kbd>Home</kbd>] and [<kbd>End</kbd>] scroll more at a time, by
+default 90% of the screen/window width or height. You can change
+the exact amount by setting the variable
+<code>scroll_more</code> in the configuration file.
+
+			<h4><a name="toc-3-4-3">3.4.3. Autoscrolling</a></h4>
+
+<p>By default, autoscrolling is disabled. You can enable it by
+setting <code>autoscroll</code> to <code>true</code> in the
+configuration file.
+
+<p>When it is enabled and the pointer is close to the edge of
+the screen/window, the map scrolls automatically. The closer you
+are to the edge, the faster it scrolls. Autoscrolling is always
+disabled near the menu bar items so that the map does not scroll
+when you're reaching for the menu.
+
+<p>You can fine tune autoscrolling by changing the variables
+<code>autoscroll_amp</code> and <code>autoscroll_edge</code>.
+
+			<h4><a name="toc-3-4-4">3.4.4. Jumping</a></h4>
+
+<p>I plan to develop a full set-mark/jump-to-mark system similar
+to the one in <code>vi</code>, with
+<code>m<var>mark-name</var></code>,
+<code>'<var>mark-name</var></code> and
+<code>`<var>mark-name</var></code>.
+
+<p>For the moment, if you press [<kbd>'</kbd>], the map scrolls
+so that its centre is at the centre of the screen/window.
+
+<p>If you press [<kbd>`</kbd>], the map scrolls so that its
+centre is at the centre of the screen/window and the zoom factor
+is adjusted so that the whole map is visible and almost fills
+the screen/window.
+
+		<h3><a name="toc-3-5">3.5. Zooming in and out</a></h3>
+
+<p>The current zoom factor is shown on the info bar, after the
+word "<code>Scale:</code>". It is shown in pixels per map
+units. The indication "<code>Scale: 50%</code>" means that one
+pixel of the display corresponds to 2 map units.
+
+<p>You can zoom in by pressing [<kbd>+</kbd>] or [<kbd>=</kbd>]
+or the 4th mouse button or by moving the mouse wheel "up". See
+the <code>zoom_default</code> and <code>zoom_step</code>
+variables.
+
+<p> You can zoom out by pressing [<kbd>-</kbd>] or
+[<kbd>_</kbd>] or the 5th mouse button or by moving the mouse
+wheel "down". See the <code>zoom_default</code> and
+<code>zoom_step</code> variables.
+
+<p> You can also set the zoom factor directly with the keys
+[<kbd>1</kbd>] through [<kbd>9</kbd>] and [<kbd>0</kbd>].
+[<kbd>1</kbd>] sets the zoom factor to a value that is
+controlled by the <code>digit_zoom_base</code> variable (by
+default, 100%). Each successive key down the keyboard sets the
+zoom factor <code>digit_zoom_step</code> percents higher than
+the previous one (by default, -29%).
+
+		<h3><a name="toc-3-6">3.6. The grid</a></h3>
+
+<p>The <dfn>grid</dfn> is a square mesh of blue dots and lines
+in the background. It's here to help you aligning your objects
+correctly with regard to Doom's metrics, which will save you a
+lot of textures misalignments.
+
+<p> When you insert or drag objects, they are <dfn><i>snapped to
+grid</i></dfn>. That is, Yadex prevents you from placing them
+off the grid. You can toggle the <code>snap_to_grid</code> flag
+by pressing [<kbd>y</kbd>].
+
+<p> The grid step is always a power of 2, E.G. 128, 64, 32, etc.
+You can get a finer grid (dividing the grid step by 2) by
+pressing [<kbd>g</kbd>]. Conversely, pressing [<kbd>G</kbd>]
+multiplies the grid step by 2. If you press [<kbd>g</kbd>] when
+the grid step is already at its minimum value, it will be set to
+its maximum value. And conversely. The minimum and maximum
+values are set in the configuration file with
+<code>grid_min</code> and <code>grid_max</code>.
+
+<p> When you change the zoom factor, Yadex automatically changes
+the grid step to make it what it thinks is best for the new zoom
+factor. If you want to lock the grid step to its current value,
+press [<kbd>z</kbd>]. To unlock it, press that key again.
+
+<p> You can hide the grid by pressing [<kbd>h</kbd>] (but this
+doesn't disable <code>snap_to_grid</code>). Press that key
+again to make the grid visible again.
+
+<p>You can also use [<kbd>H</kbd>] to reset the grid step.
+
+		<h3><a name="toc-3-7">3.7. Inserting objects</a></h3>
+
+<p>By pressing [<kbd>Ins</kbd>], you insert a new object under
+the pointer.
+
+<p>The type of the new object is generally determined by the
+current mode. That is, if you are in things mode, pressing
+[<kbd>Ins</kbd>] will create a new thing. However, this is not
+always true, particularly if some objects are already
+selected&nbsp;:
+
+<ul>
+  <li>If you are in vertices mode and there are two or more
+  vertices selected, pressing [<kbd>Ins</kbd>] will insert a
+  linedef from the first vertex to the second, another one from
+  the second to the third and so on. That is, a path of linedefs
+  is created from the first to the last vertex. The path is not
+  closed (but see [<kbd>Shift</kbd>][<kbd>Ins</kbd>] below).
+
+  <li>If you are in linedefs mode and there are selected
+  linedefs, pressing [<kbd>Ins</kbd>] will create a new sector
+  and new sidedefs that point to it and assign them to the
+  linedefs. For the linedefs that had no first sidedef (whether
+  or not they already had a second sidedef), the new sidedef is
+  attached as first sidedef. For the linedefs that had a first
+  sidedef but no second sidedef, the new sidedef is attached as
+  second sidedef.  If one or more of the selected linedefs
+  already had two sidedefs, the operation fails. Bug: the side
+  to which the new sidedef is attached is decided without taking
+  into account the actual orientation of the linedef.
+</ul>
+
+<p>If an object of the same type is highlighted at the moment
+you press [<kbd>Ins</kbd>], the properties of the new object are
+copied from the highlighted object. In other words, the
+highlighted object serves as a "model". Else the properties of
+the new object are set to default values.</p>
+
+<table>
+  <tr valign=top>
+    <th>Object type
+    <th>Property
+    <th>Value if there is a model
+    <th>Value if there is no model
+
+  <tr valign=top>
+    <td rowspan=7>Linedef
+    <td>Start vertex
+    <td>Like the model
+    <td>If there are two selected vertices, the first.
+	    If not, you are prompted for a vertex number.
+
+  <tr valign=top>
+    <td>End vertex
+    <td>Like the model
+    <td>If there are two selected vertices, the second.
+	    If not, you are prompted for a vertex number.
+
+  <tr valign=top>
+    <td>Flags
+    <td>Like the model
+    <td>Impassable
+
+  <tr valign=top>
+    <td>Type
+    <td>Like the model
+    <td>0 (normal)
+
+  <tr valign=top>
+    <td>Sector tag
+    <td>Like the model
+    <td>0 (none)
+
+  <tr valign=top>
+    <td>First sidedef
+    <td>FFFFh (none)
+    <td>FFFFh (none)
+
+  <tr valign=top>
+    <td>Second sidedef
+    <td>FFFFh (none)
+    <td>FFFFh (none)
+
+  <tr valign=top>
+    <td rowspan=4>Thing
+    <td>Coordinates
+    <td>Like the pointer
+    <td>Like the pointer
+
+  <tr valign=top>
+    <td>Type
+    <td>Like the model
+    <td><a href="#param_default_thing"><code>default_thing</code></a>
+
+  <tr valign=top>
+    <td>Flags
+    <td>Like the model
+    <td>D12 D3 D45
+
+  <tr valign=top>
+    <td>Angle
+    <td>Like the model
+    <td>0 (east)
+
+  <tr valign=top>
+    <td rowspan=7>Sector
+    <td>Floor height
+    <td>Like the model
+    <td><a href="#param_default_floor_height"><code>default_floor_height</code></a>
+
+  <tr>
+    <td>Ceiling height
+    <td>Like the model
+    <td><a href="#param_default_ceiling_height"><code>default_ceiling_height</code></a>
+
+  <tr>
+    <td>Floor texture
+    <td>Like the model
+    <td><a href="#param_default_floor_texture"><code>default_floor_texture</code></a>
+
+  <tr>
+    <td>Ceiling texture
+    <td>Like the model
+    <td><a href="#param_default_ceiling_texture"><code>default_ceiling_texture</code></a>
+
+  <tr>
+    <td>Light level
+    <td>Like the model
+    <td><a href="#param_default_light_level"><code>default_light_level</code></a>
+
+  <tr>
+    <td>Type
+    <td>Like the model
+    <td>0 (normal)
+
+  <tr>
+    <td>Tag
+    <td>Like the model
+    <td>0 (none)
+
+  <tr valign=top>
+    <td>Vertex
+    <td>Coordinates
+  </tr>
+</table>
+
+<p>In vertex mode, pressing [<kbd>Shift</kbd>][<kbd>Ins</kbd>]
+is the same as pressing [<kbd>Ins</kbd>] except that the path is
+closed (an additional linedef is created from the last to the
+first vertex).
+
+		<h3><a name="toc-3-8">3.8. Copying objects</a></h3>
+
+<p>When you press [<kbd>o</kbd>], the selected or highlighted
+object(s) is(are) copied. If only one object has been copied,
+the new copy is spawned under the pointer. If several objects
+have been copied, the new copies are spawned so that their
+centre is under the pointer.
+
+<p>The new copies are spawned selected and everything else is
+unselected so that you can easily drag them where you want.
+
+<p>All the properties of the new objects are copied from the
+original objects with the notable exception of references. If
+you are an OO programmer, think shallow copy vs. deep copy.
+Otherwise, read on.
+
+<p>When you copy linedefs, the start and end vertices are copied
+too and the new linedefs reference the new vertices instead of
+the old ones. The same thing goes for sidedefs, except if the
+<code>copy_linedef_reuse_sidedefs</code> flag is true. In that
+case, each new linedef uses the same sidedefs as its "model"
+did. This is useful when you want to create many similar
+structures, E.G. pillars that stand in the same sector. When all
+the structures use the same sidedefs, you can change all
+structures at once by editing only one of them. Another benefit
+of sharing sidedefs is that it makes your wad file somewhat
+leaner, since the sidedef, at 30 bytes, is the largest level
+object.
+
+<p>However, sharing sidedefs makes impossible to change one
+structure independantly of the others. That's where the "unlink
+sidedef" function enters. If you select one or more linedefs and
+unlink their sidedefs, Yadex makes the necessary duplications so
+that none of the sidedefs they use is also used by any other
+linedef outside the selection. Thus you can edit your linedefs
+freely. The "unlink sidedef" operation is described in detail
+<a href="#unlink_sidedefs">there</a>.
+
+<p>Similarly, when you copy sectors, the linedefs, sidedefs and
+vertices are duplicated and the new sectors use the copies, not
+the original ones. Note that the
+<code>copy_linedef_reuse_sidedefs</code> has not effect when
+copying sectors; the new linedefs always use new sidedefs, even
+if that flag is set.
+
+<p>What about copying things and vertices&nbsp;? Well, those
+don't contain references to other objects, so there are no
+special precautions to take when duplicating them. Except for
+the position, the copy is exactly identical to the original.
+
+		<h3><a name="toc-3-9">3.9. Deleting objects</a></h3>
+
+To be written. There is already a concise description in the <a
+href="getting_started.html">getting started</a> document.
+
+<br>Basically, use [<kbd>Del</kbd>].
+
+		<h3><a name="toc-3-10">3.10. Changing the properties of objects</a></h3>
+
+To be written. There is already a concise description in the <a
+href="getting_started.html">getting started</a> document.
+
+<br>Executive summary: use [<kbd>Return</kbd>] and double-click.
+
+		<h3><a name="toc-3-11">3.11. Moving objects a.k.a. drag-and-drop</a></h3>
+
+To be written. There is already a concise description in the <a
+href="getting_started.html">getting started</a> document.
+
+		<h3><a name="toc-3-12">3.12. Renumbering objects</a></h3>
+
+Normally, you don't have to worry very much about the actual
+numbers of the linedefs, sectors, sidedefs, things and vertices
+you manipulate. You just have to be careful to use the correct
+numbers in references but that's all. You don't need to
+<em>change</em> the number that a given object bears.
+
+<p>However, for certain things, the <em>relative</em> numbers of
+objects matter&nbsp;:
+
+<ul>
+  <li>if you have several player 1 starts in your level (which
+    is how the voodoo doll trick is done), it's the
+    highest-numbered one that the player incarnates in at level
+    start,
+
+  <li>if there are several teleport exits in the same sector,
+    only the lowest-numbered one is used (but I don't know of
+    any interesting application of this fact),
+
+  <li>if there are several superimposed linedefs, the
+    lowest-numbered one is drawn like it was in front,
+
+  <li>BSP's transparent doors need one of the door tracks to be
+    the lowest-numbered linedef,
+
+  <li>certain linedef types apply only to the lowest-numbered of
+    the tagged sectors (IIRC),
+
+  <li>raising stairs use the lowest-numbered linedef.
+</ul>
+
+<p>So how do you control the ordering of objects&nbsp;?
+
+			<h4><a name="toc-3-12-1">3.12.1. Exchanging objects numbers</a></h4>
+
+This function works the same way in all modes. If you select
+exactly two objects and press [<kbd>Ctrl-x</kbd>] (or use
+"Edit-&gt;Exchange objects numbers") they exchange their
+numbers. That is, if the first object had number <var>n1</var>
+and the second object had number <var>n2</var>, the first object
+in renumbered to <var>n2</var> and the second one to
+<var>n1</var>. No other objects are renumbered.
+
+<p>At the same time the numbers are exchanged, all relevant
+references are fixed up. That is, if you exchange the numbers of
+two vertices, all the linedefs that referred to them are changed
+accordingly. And if you exchange the numbers of two sectors, all
+the sidedefs that referred to them are fixed. The thing to
+remember is that this function leaves the level functionally
+identical to what it was before, except of course for the
+possible side effects of the renumbering itself.
+
+<p><small>(If you wanted (for some reason I can't imagine) to
+exchange the numbers without fixing the references, you could do
+it by replacing <code>true</code> by <code>false</code> in the
+call to <code>exchange_objects_numbers()</code>.)</small>
+
+		<h3><a name="toc-3-13">3.13. Selecting objects</a></h3>
+
+There are several ways to select objects. The simplest is to
+click on an object with the left mouse button. By default, when
+you do that, all other previously selected objects are
+unselected.
+
+<p>If you want to select an object without unselecting
+everything else, do the same thing but keep [<kbd>Ctrl</kbd>]
+pressed while you click. You can also unselect an object this
+way.
+
+<p>You can also select several objects at a time with a
+selection box. You know how to draw a selection box, don't
+you&nbsp;? Well, it works the same in Yadex. If press
+[<kbd>Ctrl</kbd>] while setting the first corner of the box, all
+objects in the box will be "toggle-selected" (that is, selected
+if they weren't, unselected if they were).
+
+<p>A more advanced way to select objects is path-selection. With
+path selection, you can easily select all the linedefs that
+form an object with a single keystroke. There are two variants
+of path selection.
+
+<p>To use the first, you must first highlight a linedef. Then
+press [<kbd>e</kbd>]. All the linedefs that belong to the same
+non-forked path as the highlighted linedef are selected. For
+example&nbsp;:</p>
+
+<table align="center">
+  <tr>
+    <td><img src="e1.png" alt="Before pressing [e]" WIDTH=159 HEIGHT=127></td>
+    <td><img src="e2.png" alt="After pressing [e]" WIDTH=159 HEIGHT=127></td>
+  </tr>
+  <tr>
+    <td align="right"><i>Before pressing</i> [<kbd>e</kbd>]</td>
+    <td align="right"><i>After pressing</i> [<kbd>e</kbd>]</td>
+  </tr>
+</table>
+
+<p>Note how the selection stop at the first fork in the
+path. That kind a path selection is good to select a path of
+single- or double-sided linedefs that belong to the same sector.
+
+<p>The other variant of path selection is better to select all
+the linedefs that form a single pillar, even if not all of its
+sides face the same sector. To use it, highlight a single-sided
+linedef and press [<kbd>E</kbd>]. All the single-sided linedefs
+that belong to the same path as the original one are
+highlighted. For example&nbsp;:</p>
+
+<table align="center">
+  <tr>
+    <td><img src="E1.png" alt="Before pressing [E]" WIDTH=156 HEIGHT=160></td>
+    <td><img src="E2.png" alt="After pressing [E]" WIDTH=154 HEIGHT=160></td>
+  </tr>
+  <tr>
+    <td align="right"><i>Before pressing</i> [<kbd>E</kbd>]</td>
+    <td align="right"><i>After pressing</i> [<kbd>E</kbd>]</td>
+  </tr>
+</table>
+
+<p>Note that the selection is not stopped by the forks in
+the path.  Also note that the double-sided linedefs are not
+selected.
+
+<p>Like clicking, [<kbd>e</kbd>] and [<kbd>E</kbd>] have the
+effect of unselecting everything else that was previously
+selected unless you use [<kbd>Ctrl</kbd>]. If [<kbd>Ctrl</kbd>]
+was pressed at the time you pressed [<kbd>e</kbd>] or
+[<kbd>E</kbd>], all the linedefs that would have been selected
+if you didn't press [<kbd>Ctrl</kbd>] are either removed from
+the selection (if they were previously selected) or added to the
+selection (if they weren't). This is actually simpler than it
+sounds.
+
+		<h3><a name="toc-3-14">3.14. The use of [<kbd>Shift</kbd>]</a></h3>
+
+<p>The [<kbd>Shift</kbd>] key has an interesting property ; as
+long as you hold it down, the highlight is locked. If an object
+is not highlighted, it stays so even if you bring the mouse
+pointer over it. Likewise, if an object is already highlighted,
+it remains so, even if you move the pointer away from it.
+
+<p>This can be useful in certain occasions, such as when you
+want to compare two sectors that have other sectors between
+them.
+
+		<h3><a name="toc-3-15">3.15. Sector miscellaneous operations</a></h3>
+
+<p>Unless otherwise specified, all the operation below act on
+all the objects in the <em>working set</em>. If there is at
+least one selected object, the working set is equal to the
+selection. If there is no selected object, the working set is
+the currently highlighted object (the object under the pointer).
+If there is no selection and no highlighted object, the
+selection is empty, of course. If there is a selection and an
+object outside the selection, the latter is <em>not</em> part of
+the working set.</p>
+
+<dl>
+  <dt>Find first free tag number
+  <dd>Displays the smallest tag number greater than 0 and not
+    used by any linedef or sector.
+
+  <dt>Rotate and scale sectors
+  <dd>(description to be written)
+
+  <dt>Make door from sector
+  <dd>(description to be written)
+
+  <dt>Make lift from sector
+  <dd>(description to be written)
+
+  <dt>Distribute sector floor heights
+  <dd>(description to be written)
+
+  <dt>Distribute sector ceiling heights
+  <dd>(description to be written)
+
+  <dt>Raise or lower sectors...
+  <dd>Prompts you for a number (N) and adds that number to the
+    floor and ceiling heights of all the sectors in the working
+    set. If N is positive, this results in raising the sectors
+    by N units. If N is negative, this results in lowering the
+    sectors by -N units.
+
+  <dt>Brighten or darken sectors...
+  <dd>Prompts you for a number (N) and adds that number to the
+    light level of all the sectors in the working set. If N is
+    positive, this results in sectors becoming brighter. If N is
+    positive, this results in sectors becoming darker. No light
+    level is decreased below 0 or increased above 255.
+
+  <dt>Unlink room
+  <dd>This function is not implemented yet.
+
+  <dt>Mirror horizontally
+  <dd>This function starts by determining the set <var>S</var>
+    of vertices that are used by the sectors in the working set.
+    Then all the vertices in <var>S</var> have their
+    x-coordinate changed so that they're "mirrored" around the
+    vertical axis that intersects the geometric centre of
+    <var>S</var>. Finally, all the linedefs whose both vertices
+    belong to <var>S</var> are flipped so that the sector
+    references remain correct.
+
+    <p>This function is designed to be used on either the whole
+    level or a group of isolated sectors (like in the
+    screenshots below). It is not recommended to use it on a
+    group of sectors if that group is connected to other
+    sectors. You can do it but the resulting mess might take you
+    some time to untangle, especially if there are many
+    connecting linedefs.
+
+    <p>A common use for this function is when you have a
+    symmetrical room with, say, the same staircase on both sides
+    of the axis of symmetry. You can build one staircase, make a
+    copy of it, mirror the copy and paste it on the other side
+    of the room.
+
+    <p>See the "Mirror horizontally" linedef function.
+
+  <dt>Mirror vertically
+  <dd>This function starts by determining the set <var>S</var>
+    of vertices that are used by the sectors in the working set.
+    Then all the vertices in <var>S</var> have their
+    y-coordinate changed so that they're "mirrored" around the
+    horizontal axis that intersects the geometric centre of
+    <var>S</var>. Finally, all the linedefs whose both vertices
+    belong to <var>S</var> are flipped so that the sector
+    references remain correct.
+
+    <p>This function is designed to be used on either the whole
+    level or a group of isolated sectors (like in the
+    screenshots below). It is not recommended to use it on a
+    group of sectors if that group is connected to other
+    sectors. You can do it but the resulting mess might take you
+    some time to untangle, especially if there are many
+    connecting linedefs.
+
+    <p>A common use for this function is when you have a
+    symmetrical room with, say, the same staircase on both sides
+    of the axis of symmetry. You can build one staircase, make a
+    copy of it, mirror the copy and paste it on the other side
+    of the room.
+
+    <p>See the "Mirror vertically" linedef function.
+
+  <dt>Swap flats
+  <dd>For each sector in the working set, exchange the floor
+    texture with the ceiling texture.
+
+</dl>
+
+		<h3><a name="toc-3-16">3.16. Thing miscellaneous operations</a></h3>
+
+<p>Unless otherwise specified, all the operation below act on
+all the objects in the <em>working set</em>. If there is at
+least one selected object, the working set is equal to the
+selection. If there is no selected object, the working set is
+the currently highlighted object (the object under the pointer).
+If there is no selection and no highlighted object, the
+selection is empty, of course. If there is a selection and an
+object outside the selection, the latter is <em>not</em> part of
+the working set.</p>
+
+<dl>
+  <dt>Find first free tag number
+  <dd>Displays the smallest tag number greater than 0 and not
+    used by any linedef or sector.
+
+  <dt>Rotate and scale things
+  <dd>(description to be written)
+
+  <dt>Spin things 45° clockwise
+  <dd>Subtract 45 to the angle of all the things in the working
+    set. This is not to be confused with "Rotate and scale
+    things" where it's the <em>position</em> of the things that
+    is changed.
+
+  <dt>Spin things 45° counter-clockwise
+  <dd>Add 45 to the angle of all the things in the working set.
+    This is not to be confused with "Rotate and scale things"
+    where it's the <em>position</em> of the things that is
+    changed.
+
+  <dt>Mirror horizontally
+  <dd>All the things in the working set have their x-coordinate
+    changed so that they're "mirrored" around the horizontal
+    axis that intersects the geometric centre of the things in
+    the working set. Their angle is also adjusted.
+
+    <p>It is not possible to mirror things without changing
+    their angle (short of commenting out a couple of lines in
+    <code>x_mirror.cc</code> and recompiling, of course).
+
+  <dt>Mirror vertically
+  <dd>All the things in the working set have their y-coordinate
+    changed so that they're "mirrored" around the horizontal
+    axis that intersects the geometric centre of the things in
+    the working set. Their angle is also adjusted.
+
+    <p>It is not possible to mirror things without changing
+    their angle (short of commenting out a couple of lines in
+    <code>x_mirror.cc</code> and recompiling, of course).
+</dl>
+
+		<h3><a name="toc-3-17">3.17. Setting/toggling/clearing thing flags</a></h3>
+
+<p>In things mode, press [<kbd>a</kbd>] to open the "set thing
+flags" popup menu. <br>Press [<kbd>b</kbd>] to open the "toggle
+thing flags" popup menu. <br>Press [<kbd>c</kbd>] to open the
+"clear thing flags" popup menu.
+
+		<h3><a name="toc-3-18">3.18. Vertex miscellaneous operations</a></h3>
+
+<p>Unless otherwise specified, all the operation below act on
+all the objects in the <em>working set</em>. If there is at
+least one selected object, the working set is equal to the
+selection. If there is no selected object, the working set is
+the currently highlighted object (the object under the pointer).
+If there is no selection and no highlighted object, the
+selection is empty, of course. If there is a selection and an
+object outside the selection, the latter is <em>not</em> part of
+the working set.</p>
+
+<dl>
+  <dt>Find first free tag number
+  <dd>Displays the smallest tag number greater than 0 and not
+  used by any linedef or sector.
+
+  <dt>Rotate and scale vertices
+  <dd>(description to be written)
+
+  <dt>Delete vertex and join linedefs
+  <dd>(description to be written)
+
+  <dt>Merge several vertices into one
+  <dd>(description to be written)
+
+  <dt>Add a linedef and split sector
+  <dd>To perform this operation, you must have exactly two
+    vertices in the working set and there must be an
+    uninterrupted path of linedefs that face a common sector
+    between them. A new linedef is inserted from the first
+    vertex to the second. The newly created sector is put on the
+    left side of the new linedef.
+
+  <dt>Mirror horizontally
+  <dd>All the vertices in the working set have their
+    x-coordinate changed so that they're "mirrored" around the
+    vertical axis that intersects the geometric centre of the
+    selected vertices.  Then all the linedefs whose both
+    vertices belong to the group of selected vertices are
+    flipped so that the sector references remain correct.
+
+    <p>See the "Mirror horizontally" linedef function.
+
+  <dt>Mirror vertically
+  <dd>All the vertices in the working set have their
+    y-coordinate changed so that they're "mirrored" around the
+    horizontal axis that intersects the geometric centre of the
+    the selected vertices. Then all the linedefs whose both
+    vertices belong to the group of selected vertices are
+    flipped so that the sector references remain correct.
+
+    <p>See the "Mirror vertically" linedef function.
+</dl>
+
+		<h3><a name="toc-3-19">3.19. Linedef miscellaneous operations</a></h3>
+
+<p>Unless otherwise specified, all the operation below act on
+all the objects in the <em>working set</em>. If there is at
+least one selected object, the working set is equal to the
+selection. If there is no selected object, the working set is
+the currently highlighted object (the object under the pointer).
+If there is no selection and no highlighted object, the
+selection is empty, of course. If there is a selection and an
+object outside the selection, the latter is <em>not</em> part of
+the working set.</p>
+
+<dl>
+  <dt>Find first free tag number
+  <dd>Displays the smallest tag number greater than 0 and not
+  used by any linedef or sector.
+
+  <dt>Rotate and scale LD &amp; SD...
+  <dd>(description to be written)
+
+  <dt>Split linedefs (add new vertex)
+  <dd>Split all linedefs in the working set, by adding a vertex
+    in the middle.
+
+    <p>The key [<kbd>x</kbd>] is a shortcut to this function.
+
+  <dt>Split linedefs and sector
+  <dd>Split both linedefs in the working set in the middle by
+    adding a vertex for each, create a linedef between the two
+    new vertices and split the sector with this new linedef.
+    There must be exactly 2 linedefs in the working set and they
+    must face a common sector.
+
+    <p>The new linedef goes from the first linedef in the
+    working set to the second linedef in the working set. The
+    new sector is on the second sidedef of the new linedef.
+
+    <p>There is a bug in this function ; if the sector contains
+    other sectors, some sidedefs are given the wrong sector
+    number.  Jim Flynn has recently fixed this in DETH. Anyone
+    to look into it&nbsp;?
+
+    <p>The key [<kbd>w</kbd>] is a shortcut to this function.
+
+  <dt>Delete linedefs and join sector
+  <dd>(description to be written)
+
+  <dt>Flip linedefs
+  <dd>The start and end vertices of the linedefs in the working
+    set are swapped. Their sidedefs are also swapped, so that
+    the sector references remain correct.
+
+    <p>If you want to flip linedefs without swapping their
+    sidedefs, you have to use "Flip linedefs" then "Swap
+    sidedefs" on them.
+
+  <dt>Swap sidedefs
+  <dd>Swap the sidedefs of the linedefs in the working set
+    <em>without</em> flipping the linedefs. This means that the
+    sector references are also swapped. If you don't understand
+    what this implies, don't use this function.
+
+  <dt>Align textures (Y offset)
+  <dd>This function is buggy.
+
+  <dt>Align textures (X offset)
+  <dd>This function is buggy.
+
+  <dt>Remove 2nd sidedef (make single-sided)
+  <dd>When two superimposed linedefs are merged, the result is
+    often a two-sided linedefs, even though the second sidedef
+    faces no sector.  Use this function to fix the mess.
+
+    <p>It sets the I flag, clears the 2 flag, sets the second
+      sidedef to -1, clears the upper and lower texture and
+      resets the middle texture to the default (as defined in
+      the preferences).
+
+  <dt>Make rectangular nook (32x16)
+  <dd>This is a single-key function to make a rectangular nook
+    in the middle of a linedef. "Nook" means that, seen from the
+    first side of the original linedef, the resulting 5 linedefs
+    form a concave figure.
+
+    <p>If the linedef is not long enough, the length of the nook
+    is one third of the length of the linedef.</p>
+
+    <table align="center">
+      <tr>
+	<td><img src="nook1.png" alt="Before" WIDTH=127 HEIGHT=159>
+	<td><img src="nook2.png" alt="After" WIDTH=127 HEIGHT=159>
+      </tr>
+      <tr>
+	<td align="right"><i>Before</i>
+	<td align="right"><i>After</i>
+      </tr>
+    </table>
+
+  <dt>Make rectangular boss (32x16)
+  <dd>Same thing as "Make rectangular nook" but the resulting
+    figure is convex.
+
+  <dt>Set length (move 1st vertex)
+  <dd>Prompts you for a length and moves the 1st vertex of the
+    linedefs in the working set so that they have the length you
+    specified.
+
+  <dt>Set length (move 2nd vertex)
+  <dd>Same thing as "Set length (move 1st vertex) but moves the
+    2nd vertex.
+
+  <dt><a name="unlink_sidedefs">Unlink 1st sidedef</a>
+  <dd>This function is used when you have several linedefs
+    sharing common sidedefs and you don't want them to share any
+    sidedefs anymore so that you can, for instance, change the
+    sector reference or texture of one of the linedefs
+    independently from the others.
+
+    <p>Here is how it works&nbsp;: all sidedefs that are used on
+    the first side of any linedef in the working set and on any
+    side of any linedef <em>not</em> in the working set are
+    duplicated and the first side of the concerned linedefs in
+    the working set is set to use the copy instead of the
+    original.
+
+    <p>Gotcha&nbsp;: note that the linedefs in the working set
+    are not "unlinked" from each other. They are only "unlinked"
+    from any other (i.e. not in the working set) linedefs.
+    Thus, if you have <em>n</em> linedefs that you want to
+    unlink from each other, you have to unlink every one of them
+    separately. This is so that, if you have, say, two square
+    pillars (2 x 4 linedefs that all use the same sidedef), you
+    can easily unlink one pillar from the other while still
+    having its 4 linedefs all use the same sidedef.
+
+  <dt>Unlink 2nd sidedef
+  <dd>Same as "Unlink 1st sidedef" but with second sidedef
+    instead of first sidedef.
+
+  <dt>Mirror horizontally
+  <dd><p>This function starts by determining the set <var>S</var>
+    of vertices that are used by any of the linedefs in the
+    working set. Then all the vertices in <var>S</var> have
+    their x-coordinate changed so that they're "mirrored" around
+    the vertical axis that intersects the geometric centre of
+    <var>S</var>. Finally, all the linedefs whose both vertices
+    belong to <var>S</var> are flipped so that the sector
+    references remain correct.</p>
+
+    <table align="center">
+      <tr>
+	<td><img src="mirror0.png" alt="Before" WIDTH=125 HEIGHT=125>
+	<td><img src="mirrorh.png" alt="After" WIDTH=125 HEIGHT=125>
+      </tr>
+      <tr>
+	<td align="right"><i>Before</i>
+	<td align="right"><i>After</i>
+      </tr>
+    </table>
+
+    <p>This function is designed to be used on either the whole
+    level or a group of isolated linedefs (like in the
+    screenshots below). It is not recommended to use it on a
+    group of linedefs if that group is connected to other
+    linedefs. You can do it but the resulting mess might take
+    you some time to untangle, especially if there are many
+    connecting linedefs.
+
+    <p>A common use for this function is when you have a
+    symmetrical room with, say, the same staircase on both sides
+    of the axis of symmetry. You can build one staircase, make a
+    copy of it, mirror the copy and paste it on the other side
+    of the room.
+
+  <dt>Mirror vertically
+  <dd><p>This function starts by determining the set <var>S</var>
+    of vertices that are used by any of the linedefs in the
+    working set. Then all the vertices in <var>S</var> have
+    their y-coordinate changed so that they're "mirrored" around
+    the horizontal axis that intersects the geometric centre of
+    <var>S</var>. Finally, all the linedefs whose both vertices
+    belong to <var>S</var> are flipped so that the sector
+    references remain correct.</p>
+
+    <table align="center">
+      <tr>
+	<td><img src="mirror0.png" alt="Before" WIDTH=125 HEIGHT=125>
+	<td><img src="mirrorv.png" alt="After" WIDTH=125 HEIGHT=125>
+      </tr>
+      <tr>
+	<td align="right"><i>Before</i>
+	<td align="right"><i>After</i>
+      </tr>
+    </table>
+
+    <p>This function is designed to be used on either the whole
+    level or a group of isolated linedefs (like in the
+    screenshots below). It is not recommended to use it on a
+    group of linedefs if that group is connected to other
+    linedefs. You can do it but the resulting mess might take
+    you some time to untangle, especially if there are many
+    connecting linedefs.
+
+    <p>A common use for this function is when you have a
+    symmetrical room with, say, the same staircase on both sides
+    of the axis of symmetry. You can build one staircase, make a
+    copy of it, mirror the copy and paste it on the other side
+    of the room.
+
+  <dt>Cut a slice out of a sector
+  <dd><p>You must select exactly two linedefs that face the same
+    sector S. This function creates a linedef A that goes from
+    the first selected linedef to the second and a linedef B
+    that goes from the second to the first. A new sector is
+    created between those four linedefs, with attributes
+    identical to those of S.</p>
+
+    <table align="center">
+      <tr>
+	<td><img src="slice1.png" alt="Before" WIDTH=150 HEIGHT=150>
+	<td><img src="slice2.png" alt="After" WIDTH=150 HEIGHT=150>
+      </tr>
+      <tr>
+	<td align="right"><i>Before</i>
+	<td align="right"><i>After</i>
+      </tr>
+    </table>
+
+    <p>This function is somewhat similar to
+    "split-linedefs-and-sector" except that it creates two
+    linedefs instead of one and that it works on doughnut-shaped
+    sectors. In fact, this function is the only one that can
+    split a sector when there is no linedef path between the
+    split points (which is the case when splitting a
+    doughnut-shaped sector between its inner and outer borders).
+
+    <p>If there is a linedef path between the selected linedefs,
+    this function is equivalent to using
+    "add-linedefs-and-split-sector" twice, except that you end
+    up with two sectors, not three. FIXME - need a figure.
+
+    <p>If the selected linedefs happen to share a vertex, only
+    one linedef is created and the new sector is triangular. The
+    linedefs must not be the same or superimposed. FIXME - need
+    a figure.
+
+    <p>Linedefs A and B are created with all their attributes
+    set to zero and their middle textures set to "<tt>-</tt>".
+    They're oriented so that their right sidedefs face the new
+    sector. Linedef A is the lowest-numbered one.
+
+    <p>The following restrictions apply&nbsp;:
+
+    <ul>
+      <li>selected linedefs must not have two sidedefs in the same sector,
+      <li>selected linedefs must not share more than one sector,
+      <li>there must be no linedef that would be superimposed with A or B.
+    </ul>
+
+    <p>These restrictions are stricter than necessary. They may
+    be lifted in the future if time and brain power permit.
+
+    <p>Because this function is not aware of the geometry of the
+    selected linedefs, but only of the sectors they face, it can
+    be used to split sectors in impossible ways. FIXME - need a
+    figure.
+
+    <p>This function assumes the space between the selected
+    linedefs is empty. If there are any other linedefs there,
+    you will have to fix their sector references manually
+    afterwards.
+
+    <p>The key [<kbd>Ctrl-k</kbd>] is a shortcut to this
+    function.
+</dl>
+
+		<h3><a name="toc-3-20">3.20. Setting/toggling/clearing linedef flags</a></h3>
+
+<p>In linedefs mode, press [<kbd>a</kbd>] to open the "set
+linedef flags" popup menu.
+<br>Press [<kbd>b</kbd>] to open the "toggle linedef flags" popup menu.
+<br>Press [<kbd>c</kbd>] to open the "clear linedef flags" popup menu.
+
+		<h3><a name="toc-3-21">3.21. Undoing</a></h3>
+
+<p>As of this release, undoing is not implemented.
+
+		<h3><a name="toc-3-22">3.22. Cut-and-paste from one level to another</a></h3>
+
+<p>As of this release, it's not possible.
+
+		<h3><a name="toc-3-23">3.23. Using the flat/patch/sprite/texture viewer</a></h3>
+
+<p>Flats, patches, sprites and textures are browsed and selected
+with the same basic tool, snappily named the
+flat/patch/sprite/texture viewer. How do you use that
+beast&nbsp;?
+
+<p><img src="vflat.png" alt="Browsing flats" WIDTH=315 HEIGHT=86>
+
+<p><img src="vsprite.png" alt="Browsing sprites" WIDTH=379 HEIGHT=149>
+
+<p><img src="vtexture.png" alt="Browsing textures" WIDTH=507 HEIGHT=149>
+
+<p>You can change the current name simply by typing it. Use
+[<kbd>Backspace</kbd>] to erase the rightmost character. As you
+type, the list of names scrolls automatically so that the first
+line of the list shows the first valid name that begins with the
+characters in the entry box. If the current name does not belong
+to the list, it is grayed out and you can't validate. If it
+does, the corresponding image is shown in the box to the right.
+
+<p>As in certain Unix programs, [<kbd>Tab</kbd>] is used for
+name completion. If the current name is "<code>SW1</code>" and
+you press [<kbd>Tab</kbd>], the current name is set to the first
+name that begins with "<code>SW1</code>".
+
+<p>[<kbd>Ctrl-u</kbd>] and [<kbd>Ctrl-w</kbd>] clear the current
+name, like pressing [<kbd>Backspace</kbd>] repeatedly would.
+
+<p>You can also move through the list without typing
+names&nbsp;:
+
+<ul>
+  <li>[<kbd>Up</kbd>] and [<kbd>Down</kbd>] move to the previous
+  or next name in the list.
+
+  <li>[<kbd>Pgup</kbd>] and [<kbd>Pgdn</kbd>] move one page at a
+  time.
+
+  <li>[<kbd>Home</kbd>] and [<kbd>End</kbd>] move you to the
+  first or last name of the list.
+
+  <li>[<kbd>Ctrl-b</kbd>] does the same thing as
+  [<kbd>Pgup</kbd>].
+
+  <li>[<kbd>Ctrl-f</kbd>] and [<kbd>Ctrl-v</kbd>] do the same
+  thing as [<kbd>Pgdn</kbd>].
+</ul>
+
+
+<p>To validate the current name as your choice, press
+[<kbd>Return</kbd>]. If the current name is grayed-out
+(invalid), [<kbd>Return</kbd>] does not work. To cancel, press
+[<kbd>Esc</kbd>].
+
+<p>[<kbd>Shift-F1</kbd>] saves the current image to file, in
+packed PPM (<tt>P6</tt>) format. This can be useful for
+textures, that cannot be directly extracted from wads.
+Transparent areas are represented according to the DeuTex
+convention by colour rgb:0/2f/2f (<img src="002f2f.png"
+alt="Swatch" width="8" height="8">). The file is created in the
+working directory and its name is the name of the image
+lowercased and suffixed by "<tt>.ppm</tt>".  For example, flat
+"<tt>FLOOR0_7</tt>" would be saved as "<tt>./floor0_7.ppm</tt>".
+If the file already exists, it's mercilessly overwritten.
+
+<p>Note that under MS-DOS, newlines in the PPM header are in
+Unix format (LF, not CR LF).</p>
+
+<p>There are a few bugs left in this function. Textures are
+clipped to the dimension of the viewer window. Under MS-DOS,
+some "<tt>VILE*</tt>" sprites will not save, because their names
+contain characters that are not allowed in file names
+("<tt>[</tt>", "<tt>\</tt>" and "<tt>]</tt>").
+
+<p>[<kbd>F1</kbd>] prints to stdout the location (file name and
+offset) of the current flat, patch or sprite. For debugging
+purposes.
+
+<p>When viewing textures, you may press [<kbd>Ctrl-a</kbd>] and
+[<kbd>Ctrl-x</kbd>] to cycle through the patches that make up
+the texture.
+
+<p>Finally when viewing sprites, two other useful commands are
+[<kbd>Ctrl-n</kbd>] and [<kbd>Ctrl-p</kbd>]. These go
+respectively to the next and previous group of sprites (all
+sprites that have the same first 4 letters belong to the same
+group). It's handy to skip the 69 animation frames of the heavy
+weapon dude at once.
+
+		<h3><a name="toc-3-24">3.24. Saving</a></h3>
+
+<p>There are two ways to save&nbsp;:
+
+<ul>
+  <li><p>Press [<kbd>F2</kbd>] or do "File-&gt;Save". If the level
+    comes from the iwad or if its level name or file name is
+    unknown (because it's a new level), you are prompted for a
+    level name (EnMn or MAPnm) and a file name first. If the
+    file name has changed since the last time you saved, and if
+    a file of that name already exists, you are asked
+    confirmation before saving.
+
+    <p>The level in the window is saved in the specified file,
+    in the pwad format, under the specified .
+
+  <li><p>Press [<kbd>F3</kbd>] or do "File-&gt;Save as".
+    This procedure is identical to the "Save" procedure except
+    that the query for a level name and file name is
+    unconditional.
+</ul>
+
+<p>FIXME -- this needs to be written...
+
+<p>If Yadex is in Hexen mode, saving is disabled because writing
+levels in the Hexen format is not supported as of this release.
+
+
+
+		<h3><a name="toc-3-25">3.25. Closing a window</a></h3>
+
+<p>There are two ways to close a window&nbsp;:
+
+<ul>
+  <li><p>Press [<kbd>Esc</kbd>]. If you have made changes since the
+    last time you saved, or if you have never saved, Yadex
+    requires confirmation before closing the window.
+
+  <li><p>Press [<kbd>q</kbd>] or do "File-&gt;Quit". If
+    you have made changes since the last time you saved, or if
+    you have never saved, Yadex first saves the level, using the
+    same procedure as when you press [<kbd>F2</kbd>]. After that
+    the window is closed. If the saving procedure is interactive
+    (for example because it's the first time you save), and if
+    you cancel it, the window is not closed.
+
+</ul>
+
+	<hr noshade>
+	<h2><a name="toc-4">4. Variables and configuration</a></h2>
+
+<p>
+  Yadex has internal variables that serve to configure its
+  behaviour. Variables have a name (a string of letters, digits
+  and underscores), a type and a value. The type constraints
+  the value (boolean, integer, strings, etc.).
+</p>
+
+<p>
+  Variables can be set in four ways&nbsp;: 
+</p>
+
+<ul>
+  <li>from the Preferences menu,
+  <li>from the command line,
+  <li>through environment variables.
+  <li>from the configuration files,
+</ul>
+
+<p>
+  The settings from the Preferences menu override those from the
+  command line options which in turn override those from the
+  environment variables which in turn override those from the
+  configuration files.
+</p>
+
+		<h3><a name="toc-4-1">4.1. Variables</a></h3>
+
+<p>
+  You can get a list of variables with their description and value
+  by typing <code>set</code> at the <code>yadex:</code> prompt.
+</p>
+
+			<h4><a name="toc-4-1-1">4.1.1. The font</a></h4>
+
+<p>
+  By default, Yadex uses the default font of your system (that
+  is often "<code>fixed</code>" a.k.a. "<code>6x13</code>"). But
+  you can use the font of your choice by using the "<code>-fn
+  </code><var>font_name</var>" option or setting
+  "<code>font&nbsp;=&nbsp;</code><var>font_name</var>" in
+  <code>yadex.cfg</code>. You should use a fixed-width font and
+  not one that is too large for the size of your Yadex window or
+  the display will look ugly. If Yadex does not find the
+  specified font, it emits a warning and falls back on the
+  default system font.
+</p>
+
+<p>
+  You can get a list of all available fonts on your system with
+  the command <code>xlsfonts</code>.
+</p>
+
+			<h4><a name="toc-4-1-2">4.1.2. Mouse wheel and other mouse issues</a></h4>
+
+<p>
+  The 3rd mouse button (middle button) is not used yet but you
+  can bet it will a future version. So a 3-button mouse is of
+  course recommended.
+</p>
+
+<p>
+  You can swap the left and right buttons by setting the <a
+  href="#param_swap_buttons"><code>swap_buttons</code></a>
+  variable.
+</p>
+
+<p>
+  Buttons 4 and 5 are used for zooming in and out. Wheel mice
+  typically have the wheel mapped to buttons 4 and 5 in such a
+  way that when you roll the wheel "up" (forwards), button4
+  press events are generated and when you roll the wheel "down"
+  (backwards), button5 press events are generated.
+</p>
+  
+<p>
+  To configure your X server in the way described above, check
+  the vendor documentation. I have XFree86 and a Logitech Pilot
+  Mouse + and this is what I put in my <code>XF86Config</code>
+  file&nbsp;:
+</p>
+
+<blockquote>
+  <pre>Section "Pointer"
+    Protocol      "Intellimouse"
+    Device        "/dev/mouse"
+    Buttons       5
+    ZAxisMapping  4 5</pre>
+</blockquote>
+
+		<h3><a name="toc-4-2">4.2. Preferences</a></h3>
+
+<p>
+  When you create objects, their properties are automatically
+  given default values. Some of those default values can be set
+  from the configuration file or from the command line but also
+  through the Preferences menu, that pops up when you press
+  [<kbd>F5</kbd>].
+</p>
+
+<p>
+  The Preferences menu lets you set the <code>default_*</code>
+  variables interactively. The settings made from the
+  Preferences menu are lost when you exit Yadex.
+</p>
+
+		<h3><a name="toc-4-3">4.3. Command line</a></h3>
+
+<p>
+  See the <a href="#opt">Options</a> section.
+</p>
+
+		<h3><a name="toc-4-4">4.4. Environment variables</a></h3>
+
+<p>
+  See the <a href="#env">Environment variables</a> section.
+</p>
+
+		<h3><a name="toc-4-5">4.5. Configuration files</a></h3>
+
+			<h4><a name="toc-4-5-1">4.5.1. Contents of configuration files</a></h4>
+
+<p>Configuration files are text files. White space at the
+beginning of a line is ignored. There are three kinds of
+lines&nbsp;:
+
+<dl>
+  <dt>Empty lines (lines containing only white space)
+  <dd>
+    <p>
+      No effect.
+    </p>
+  
+  <dt>Comments (lines whose first non white space character is a
+      <code>#</code>)
+  <dd>
+    <p>
+      No effect.
+    </p>
+
+  <dt>Variable assignments (lines of the form "<i>name</i>
+      <code>=</code> <i>value</i>")
+  <dd>
+    <p>The effect is to assign <i>value</i> to the variable
+      <i>name</i>. <i>name</i> is a string of one or more
+      <i>identifier characters</i> i.e. letters, digits and
+      underscores. <i>value</i> is a string of zero or more
+      non white space characters. There may be any amount of
+      white space around and between the three tokens, including
+      none at all.
+    </p>
+
+    <p>
+      Please note that&nbsp;:
+    </p>
+
+    <ul>
+      <li>
+        <p>
+	  <code>#</code> is special only at the beginning of a
+	  line. Therefore you can't put a comment on the same
+	  line as a variable assignment.
+	</p>
+      </li>
+
+      <li>
+        <p>
+	  Because white space is a token delimiter and there's
+	  no way to quote or escape it, including white space in
+	  a value is impossible.
+	</p>
+      </li>
+
+      <li>
+        <p>
+	  Yadex's idea of what is a letter or digit is
+	  deliberately locale-independent. Whether it's white
+	  space or not, on the other hand, is locale-dependent
+	  (<code>isspace</code>(3)).
+	</p>
+      </li>
+    </ul>
+</dl>
+
+<p>
+  Parse errors are not fatal. In general, they cause a warning
+  message to be printed and the entire line to be ignored. This
+  is to facilitate the sharing of configuration files across
+  versions of Yadex.
+</p>
+
+<p>
+  The configuration file is self-documenting. Look at the sample
+  configuration file in the Yadex distribution to see what
+  options are available.
+</p>
+
+			<h4>4.5.2. <a name="config_locate">Locating
+			configuration files</a></h4>
+
+<p>
+  This is the process by which Yadex turns a configuration file
+  name into one or more actual pathnames.
+</p>
+
+<p>
+  If the specified name is absolute, the location yields exactly
+  that. A name is considered absolute if and only if it begins
+  with a <code>/</code>.
+</p>
+
+<p>
+  If the specified name is relative, Yadex uses a search path,
+  much like the shell uses <code>$PATH</code> to locate
+  commands. The composition of the search path depends on the
+  installation prefix (the argument to <code>./configure
+  --prefix</code>).
+</p>
+
+<dl>
+  <dt><code>/usr/local</code> or <code>/usr</code>&nbsp;:
+  <dd>
+    <ol>
+      <li><code>.</code>
+      <li><code>~/.yadex/$VERSION</code>
+      <li><code>~/.yadex</code>
+      <li><code>/etc/yadex/$VERSION</code>
+      <li><code>/etc/yadex</code>
+    </ol>
+
+  <dt><code>/opt/<var>some/path</var></code>&nbsp;:
+  <dd>
+    <ol>
+      <li><code>.</code>
+      <li><code>~/.yadex/$VERSION</code>
+      <li><code>~/.yadex</code>
+      <li><code>/etc/opt/<var>some/path</var></code>
+    </ol>
+
+  <dt><code><var>/some/path</var></code>&nbsp;:
+  <dd>
+    <ol>
+      <li><code>.</code>
+      <li><code>~/.yadex/$VERSION</code>
+      <li><code>~/.yadex</code>
+      <li><code><var>/some/path</var>/etc</code>
+    </ol>
+</dl>
+
+<p>
+  The search path may be walked in either direction, depending
+  on the application. For each element in the search path, a
+  pathname is made by concatenating the path and the specified
+  name. The pathname is tested with <code>stat</code>(2). The
+  result of the location is the list of the pathnames that exist
+  and are not directories.
+</p>
+
+<p>
+  For example, assuming Yadex was compiled with the
+  <code>/usr/local</code> prefix, a front-to-back search for a
+  file named <code>foo/bar.cfg</code> would return those of the
+  following pathnames that exist and are not directories&nbsp;:
+</p>
+
+<ol>
+  <li><code>./foo/bar.cfg</code>
+  <li><code>~/.yadex/$VERSION/foo/bar.cfg</code>
+  <li><code>~/.yadex/foo/bar.cfg</code>
+  <li><code>/etc/yadex/$VERSION/foo/bar.cfg</code>
+  <li><code>/etc/yadex/foo/bar.cfg</code>
+</ol>
+
+			<h4><a name="toc-4-5-3">4.5.3. Default configuration files</a></h4>
+
+<p>
+  By default, Yadex performs a back-to-front search for files
+  named <code>yadex.cfg</code> and reads all the matches in
+  order. For example, assuming Yadex was compiled with the
+  <code>/usr/local</code> prefix, the following configuration
+  files will be read if they exist&nbsp;:
+</p>
+
+<ol>
+  <li><code>/etc/yadex/yadex.cfg</code>
+  <li><code>/etc/yadex/$VERSION/yadex.cfg</code>
+  <li><code>~/.yadex/yadex.cfg</code>
+  <li><code>~/.yadex/$VERSION/yadex.cfg</code>
+  <li><code>./yadex.cfg</code>
+</ol>
+
+<p>
+  Because the search path is walked back-to-front, any parameter
+  settings in a local configuration file override the settings
+  inherited from less local configuration files. For example,
+  assuming <code>/etc/yadex/$VERSION/yadex.cfg</code>
+  contains&nbsp;:
+</p>
+
+<blockquote>
+  <code>
+    a = old<br>
+    b = old
+  </code>
+</blockquote>
+
+<p>
+  and <code>./yadex.cfg</code> contains&nbsp;:
+</p>
+
+<blockquote>
+  <code>
+     a = new<br>
+     c = new
+  </code>
+</blockquote>
+
+<p>
+  the net effect is&nbsp;:
+</p>
+
+<blockquote>
+  <code>
+     a = new<br>
+     b = old<br>
+     c = new
+  </code>
+</blockquote>
+
+			<h4><a name="toc-4-5-4">4.5.4. User-specified configuration files</a></h4>
+
+<p>
+  The <code>-f</code> option can be used to override Yadex's
+  default choice of configuration files.
+</p>
+
+<p>
+  If Yadex is started with the <code>-f</code> option, the
+  default configuration files are not used. Instead, Yadex
+  performs a front-to-back search for the argument of the
+  <code>-f</code> option, according to the algorithm described
+  in <a href="#config_locate">Locating configuration files</a>.
+  The first match is used as a configuration file. Any other
+  matches are ignored.
+</p>
+
+<p>
+  For example, assuming Yadex was built with the
+  <code>/usr/local</code> prefix and run with the
+  <code>-f&nbsp;myown.cfg</code> option, it will use the first
+  file in this list that exists and is not a directory&nbsp;:
+</p>
+
+<ol>
+  <li><code>./myown.cfg</code>
+  <li><code>~/.yadex/$VERSION/myown.cfg</code>
+  <li><code>~/.yadex/myown.cfg</code>
+  <li><code>/etc/yadex/$VERSION/myown.cfg</code>
+  <li><code>/etc/yadex/myown.cfg</code>
+</ol>
+
+			<h4><a name="toc-4-5-5">4.5.5. Organising your configuration files</a></h4>
+
+<p>
+  As Yadex looks for its configuration files in several places,
+  you are put in the situation of having to decide which one to
+  use. Here are a few guidelines to help you make a decision.
+</p>
+
+<dl>
+  <dt>Avoid redundancy
+  <dd>
+    <p>
+      Take advantage of Yadex's ability to use more than one
+      config file. Put each setting in the right place. Your
+      config files will be easier to read and maintain.
+    </p>
+
+  <dt>Versionless vs. versionful files
+  <dd>
+    <p>
+      Versionful files
+      (<code>/etc/yadex/$VERSION/yadex.cfg</code> and
+      <code>~/.yadex/$VERSION/yadex.cfg</code>) are useful to
+      store settings that only work with a particular version of
+      Yadex. But remember that the versionful system-wide file
+      can be clobbered by a reinstallation.
+    </p>
+
+    <p>
+      Versionless files (<code>/etc/yadex/yadex.cfg</code> and
+      <code>~/.yadex/yadex.cfg</code>) have the advantage of
+      being seen by all versions of Yadex. If you enter your
+      settings there, you won't have to enter them again when
+      you install a new version of Yadex, as long as the config
+      file syntax remains compatible. 
+    </p>
+
+  <dt>System-wide vs. user vs. local files
+  <dd>
+    <p>
+      System-wide configuration files have the theoretical
+      advantage of being seen by all users, which makes them a
+      good place to put settings that apply to everybody, such
+      as the pathnames of the iwads. Of course, it doesn't make
+      any difference for the typical (single-user) Yadex
+      installation.
+    </p>
+
+    <p>
+      Per-user files (the ones in <code>~/.yadex</code>) are
+      appropriate for settings that have to do with personal
+      preferences (fonts etc.). They also have the advantage
+      over system-wide files of not being overwritten by the
+      installation procedure (typing <code>make install</code> a
+      second time will wipe the versionful system file).
+    </p>
+
+    <p>
+      Local files (<code>./yadex.cfg</code>) are well suited to
+      settings that vary from project to project, such as
+      default textures.
+    </p>
+</dl>
+
+<p>
+  Concrete application&nbsp;: Yadex was compiled with
+  <code>/usr/local</code> as the prefix. You are the only user
+  on your system. All your levels are for Doom&nbsp;2, except
+  the one in <code>~/herewad</code> which is for Heretic. One of
+  your Doom&nbsp;2 levels (<code>~/cave</code>) is quite dark
+  and requires a different default light level. You usually run
+  Yadex from the directory where the pwad is.
+</p>
+
+<p>
+  There are several ways to configure Yadex for this setup.
+  Here's a solution in accordance with the above
+  guidelines&nbsp;:
+</p>
+
+<p>
+  <code>~/.yadex/yadex.cfg</code>&nbsp;:
+</p>
+
+<blockquote>
+  <pre>iwad2 = /somewhere/doom2.wad
+iwad3 = /somewhere/else/heretic.wad
+game  = doom2</pre>
+</blockquote>
+
+<p>
+  <code>~/herewad/yadex.cfg</code>&nbsp;:
+</p>
+
+<blockquote>
+  <pre>game                    = heretic
+default_floor_texture   = floor11
+default_ceiling_texture = floor06
+default_lower_texture   = sandsq2
+default_middle_texture  = sandsq2
+default_upper_texture   = sandsq2
+default_thing           = 66</pre>
+</blockquote>
+
+<p>
+  <code>~/cave/yadex.cfg</code>&nbsp;:
+</p>
+
+<blockquote>
+  <pre>default_light_level = 112</pre>
+</blockquote>
+
+<p>
+  Note how <code>game</code> is set in the per-user config file
+  (the general case) and overridden in the local config file for
+  Heretic level (the exception).  
+</p>
+
+	<hr noshade>
+	<h2><a name="toc-5">5. Game definition files</a></h2>
+
+<p>
+  Most of Yadex's knowledge about thing numbers and names,
+  linedef types etc. is retrieved from so-called game definition
+  files. When you specify "<code>-g&nbsp;foo</code>", it in
+  fact means that Yadex should use the game definition file
+  named "<code>foo.ygd</code>".
+</p>
+
+		<h3><a name="toc-5-1">5.1. Contents of game definition files</a></h3>
+
+<p>
+  For Yadex to recognize the file as a game definition file, it
+  must begin with a certain magic string. If it doesn't, Yadex
+  will print an error message an bail out. The reason for being
+  so fussy is to avoid headaches when the game definition file
+  format changes and there are old game definition files lying
+  around in your directories.
+</p>
+
+<p>
+  Game definition files are not supposed to be modified in
+  normal use. Their format is described in <a
+  href="ygd.html"><code>ygd.html</code></a>.
+</p>
+
+		<h3>5.2. <a name="ygd_locate">Locating game definition
+		files</a></h3>
+
+<p>
+  The algorithm used to locate game definition files is exactly
+  the same as the one described in  <a
+  href="#config_locate">Locating configuration files</a>. Only
+  the search path is different. As is the case for config files,
+  it depends on the prefix for which Yadex was compiled.
+</p>
+
+<dl>
+  <dt><code>/usr</code>&nbsp;:
+  <dd>
+    <ol>
+      <li><code>.</code>
+      <li><code>~/.yadex/$VERSION</code>
+      <li><code>~/.yadex</code>
+      <li><code>/usr/share/games/yadex/$VERSION</code>
+      <li><code>/usr/share/games/yadex</code>
+    </ol>
+
+  <dt><code>/usr/local</code>&nbsp;:
+  <dd>
+    <ol>
+      <li><code>.</code>
+      <li><code>~/.yadex/$VERSION</code>
+      <li><code>~/.yadex</code>
+      <li><code>/usr/local/share/games/yadex/$VERSION</code>
+      <li><code>/usr/local/share/games/yadex</code>
+    </ol>
+
+  <dt><code>/opt/<var>some/path</var></code>&nbsp;:
+  <dd>
+    <ol>
+      <li><code>.</code>
+      <li><code>~/.yadex/$VERSION</code>
+      <li><code>~/.yadex</code>
+      <li><code>/opt/<var>some/path</var>/share</code>
+    </ol>
+
+  <dt><code><var>/some/path</var></code>&nbsp;:
+  <dd>
+    <ol>
+      <li><code>.</code>
+      <li><code>~/.yadex/$VERSION</code>
+      <li><code>~/.yadex</code>
+      <li><code><var>/some/path</var>/share</code>
+    </ol>
+</dl>
+
+		<h3><a name="toc-5-3">5.3. Use of game definition files</a></h3>
+
+<p>
+  On startup, Yadex loads the game definition file corresponding
+  to the <code>game</code> variable. It performs a front-to-back
+  search (see <a href="#ygd_locate">Locating game definition
+  files</a>) for a file named <code><var>game</var>.ygd</code>.
+  The first match is used.
+</p>
+
+	<hr noshade>
+	<h2><a name="toc-6">6. Known bugs</a></h2>
+
+<p>Though Yadex has quite a few bugs, most of them are
+inconsequential, i.e. not likely to make Yadex unusable or
+damage precious data. On the other hand, <strong>some can
+bite</strong>. Those are the ones you should know about&nbsp;:
+
+<ul>
+  <li>
+    <p>Command line options that take an argument need to have
+    a space between their argument and themselves.</p>
+
+  <li>
+    <p>Exposure events are not always handled.  If the Yadex
+    window turns black, back out by pressing [<kbd>Esc</kbd>],
+    several times if necessary.</p>
+
+  <li>
+    <p>If you edit a level from a file that contains several and
+    save it, all the other levels, textures, flats, etc. from
+    that file are <strong>lost</strong>.</p>
+
+  <li>
+    <p>Out-of-memory conditions and certain wad I/O errors are
+    handled in a <em>very</em> ungraceful manner. Basically,
+    Yadex aborts and if you haven't saved, you've lost all your
+    work. My advice&nbsp;:</p>
+
+    <ul>
+      <li>Make sure you have at least a couple of megs of free
+	memory.
+      <li>Save often and make backups.
+      <li>Don't use wads that contain errors.
+      <li>Make sure you have enough disk space and adequate
+	permissions.
+      <li>Don't modify files with an external program while
+	Yadex uses them. For example, if you use a texture wad,
+	don't rebuild it without quitting Yadex first.
+    </ul>
+</ul>
+
+<p>Check <a href="TODO"><code>TODO</code></a> for a complete
+list of things to fix.
+
+	<hr noshade>
+	<h2>7. <a name="games">Supported games</a></h2>
+
+		<h3><a name="toc-7-1">7.1. Doom</a></h3>
+
+<p>Supported. Linedef types and sector types added in v. 1.666
+are supported and marked with "<code>[v1.6]</code>".
+
+		<h3><a name="toc-7-2">7.2. Doom II</a></h3>
+
+<p>Supported.
+
+		<h3><a name="toc-7-3">7.3. Doom alpha</a></h3>
+
+<p>Mostly supported. There are three Doom alpha versions that I
+know of&nbsp;: <a
+href="ftp://3darchives.in-span.net/pub/idgames/historic/doom0_2.zip">0.2</a>,
+<a
+href="ftp://3darchives.in-span.net/pub/idgames/historic/doom0_4.zip">0.4</a>
+and <a
+href="ftp://3darchives.in-span.net/pub/idgames/historic/doom0_5.zip">0.5</a>.
+They're supported to varying degrees of completeness. All
+graphics resources (flats, patches, <code>PLAYPAL</code>,
+sprites and textures) are supported for all versions with the
+exception of version 0.2, for which textures are not supported.
+
+<p>Reading levels does not work either for version 0.2. For
+version 0.4 and 0.5, it works, including levels
+<code>E1M10</code> through <code>E1M13</code>. There are some
+oddities in the levels, such as linedefs with negative types or
+things with strange bits set in their flags, but I don't think
+it's Yadex's fault.
+
+<p>You can edit and save alpha levels but they will be saved in
+the regular Doom format, not the alpha format. Writing levels in
+the Doom alpha format is not supported at all and probably never
+will, for three reasons. Firstly, there are parts of the format
+that I don't understand, and therefore don't know how to
+generate. Secondly, there is AFAIK no nodes builder for the
+alphas. Thirdly, even if the two above problems were solved, I
+don't expect many people to actually want to use the alphas
+because, from a player point of view, they're much less
+comfortable than the later versions of Doom. To say nothing of
+the fact that all we have is a DOS executable and no source
+code. That being said, I can't deny that it would indeed be cool
+to be able to generate wads for the alphas, if only for the fun
+of it. If you want to do it, I won't discourage you and I will
+gladly accept patches.
+
+		<h3><a name="toc-7-4">7.4. Doom press release pre-beta</a></h3>
+
+<p>Supported. The different picture format is handled. Things
+type 2016 (evil sceptre) and 2017 (unholy bible) are defined in
+<code>doom02.ygd</code>, <code>doom04.ygd</code>,
+<code>doom05.ygd</code>, <code>doompr.ygd</code>,
+<code>doom.ygd</code> and <code>doom2.ygd</code> and marked with
+"<code>[PR]</code>".  However, if you're using
+<code>betalevl.wad</code> and <code>betagrph.wad</code> supplied
+with MBF, you won't see the corresponding sprites because Yadex
+does not support sprites in pwads (yet). To see the sprites for
+the evil sceptre and the unholy bible as well as the alternate
+versions of the other sprites, you need to use the iwad from <a
+href="ftp://3darchives.in-span.net/pub/idgames/historic/doomprbt.zip"
+><code>doomprbt.zip</code></a>.
+
+		<h3><a name="toc-7-5">7.5. Final Doom</a></h3>
+
+<p>Supported, AFAIK. The iwads have no
+<code>F1_START/F1_END</code> labels and some levels contain a
+thing of type 0 which made older versions of Yadex crash. This
+has been fixed in version 1.1.0.
+
+		<h3><a name="toc-7-6">7.6. Heretic</a></h3>
+
+<p>Supported.
+
+		<h3><a name="toc-7-7">7.7. Hexen</a></h3>
+
+<p>Very rudimentary support. You can load Hexen wads and edit
+the maps but most of Hexen's special features are stripped off
+on reading. So don't try to save a Hexen level after editing it,
+you won't be able to use it with Hexen. And if you're saving it
+to the file it comes from, you'll lose your file. <strong>Don't
+save when in Hexen mode.</strong>. Here's the breakdown&nbsp;:
+
+<ul>
+  <li>Most thing types, and some sector and linedef types are
+    missing from <code>hexen.ygd</code>.
+  <li>For things, <code>tid</code>, <code>z</code>,
+    <code>special</code> and <code>arg1</code> through
+    <code>arg5</code> are discarded. There is currently no way
+    to examine or manipulate them from Yadex.
+  <li>For linedefs, <code>arg1</code> is put into
+    <code>tag</code>. <code>arg2</code> through
+    <code>arg5</code> are discarded and there is currently no way
+    to examine or manipulate them from Yadex.
+  <li>The Hexen-specific thing and linedef flags are not
+    recognized (but you can manipulate them).
+  <li><code>BEHAVIOR</code> is ignored.
+  <li><code>MAPINFO</code> is ignored.
+</ul>
+
+		<h3><a name="toc-7-8">7.8. Strife</a></h3>
+
+<p>Supported, except that&nbsp;:
+
+<ul>
+  <li>many thing types are missing,
+  <li>some thing flags are not known,
+  <li>many linedef types are missing or wrong,
+  <li>some linedef flags might be missing,
+  <li>some sector types might be missing.
+</ul>
+
+And perhaps other things as well. If you're a Strife hacker,
+your help would be welcome.
+
+<p>If you have Strife 1.0, you should use
+<code>-g&nbsp;strife10</code>. Strife&nbsp;1.0 uses the same
+format as Doom for textures, Strife&nbsp;1.1 and later use a
+different format.
+
+		<h3><a name="toc-7-9">7.9. Ultimate Doom</a></h3>
+
+<p>Supported.
+
+		<h3><a name="toc-7-10">7.10. Boom</a></h3>
+
+<p>Kind of supported, only very inconvenient to use &lt;g&gt;.
+
+<dl>
+  <dt>New linedef flag "P" (pass through)
+  <dd>Supported.
+
+  <dt>New linedef types
+  <dd>You can enter arbitrary linedef types ("enter number").
+
+  <dt>New sector types
+  <dd>You can enter arbitrary sector types ("enter number")
+
+  <dt>New things flags "N" (not in deathmatch) and "C" (not in coop)
+  <dd>Supported.
+
+  <dt>New things types 5001 and 5002
+  <dd>Supported.
+
+  <dt>Special lumps <code>SWITCHES</code> and <code>ANIMATED</code>
+  <dd>Unsupported.
+</dl>
+
+In progress...
+
+		<h3><a name="toc-7-11">7.11. EDGE</a></h3>
+
+<p>The default DDF definitions included in EDGE 1.24 have been
+added to <code>doom.ygd</code> and <code>doom2.ygd</code>,
+marked with "<code>[EDGE]</code>". When the pointer moves over a
+sector that has extrafloors, the object info window shows the
+information relevant to those. To see the sprite for the night
+vision goggles (thing #7000), you must load
+<code>edge.wad</code>.
+
+<p>As of 1.5.0, the support for DDF is static&nbsp;: custom DDF
+files or DDF lumps are ignored. In other words, you are limited
+to the default DDF definitions.
+
+		<h3><a name="toc-7-12">7.12. MBF</a></h3>
+
+<p>Mostly supported, I think. Thing 888 (dog), thing flag 80h
+(friendly), linedef types 271 and 272 are all in. You can't see
+the sprite for the dog because it's embedded in the MBF
+executable.
+
+		<h3><a name="toc-7-13">7.13. Other derivatives</a></h3>
+
+<p>Not supported so far.</p>
+
+<hr>AYM $SELF_DATE
+</body>
+</html>
Binary file docsrc/vflat.png has changed
Binary file docsrc/vsprite.png has changed
Binary file docsrc/vtexture.png has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/docsrc/wad_specs.html	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,133 @@
+<html>
+<head>
+<title>Yadex wad specs</title>
+</head>
+<body>
+
+<div align="center">
+<img src="logo_small.png" alt="Fancy logo">
+<br>Yadex $VERSION ($SOURCE_DATE)
+<h1>Wad specs</h1>
+<table><tr><td></td><td width="50%" align="center">
+This document describes the characteristics of the wads that
+Yadex accepts and generates.
+<td></td></table>
+</div>
+<br>
+<br>
+<br>
+
+	<h2>Wad data types</h2>
+
+<dl>
+<a name="i32"><dt><code>i32</code></a>
+<dd>An array of 4 bytes that is interpreted as a little-endian
+signed 32-bit integer. The array is always interpreted as
+little-endian, even if the platform is not. By definition, the
+value of an <code>i32</code> can be between
+-2&nbsp;147&nbsp;483&nbsp;648 and +2&nbsp;147&nbsp;483&nbsp;647.
+
+
+<a name="i16"><dt><code>i16</code></a>
+<dd>An array of 2 bytes that is interpreted as a little-endian
+signed 16-bit integer. The array is always interpreted as
+little-endian, even if the platform is not. By definition, the
+value of an <code>i16</code> can be between -32&nbsp;768 and
++32&nbsp;767.
+
+</dl>
+
+	<h2>Wad header</h2>
+
+		<h3>Input</h3>
+
+An iwad or pwad must be at least 12 bytes long or it will be
+rejected. It must start with the string "<code>IWAD</code>" or
+"<code>PWAD</code>" (the matching is case sensitive), otherwise
+it will be rejected.
+
+<p>The next 4 bytes contain the number of entries in the
+directory as an <a href="#i32"><code>i32</code></a>. If this
+field is 0, the whole wad should be ignored (but I'm not sure it
+is in practice--TBF). If this field is negative, the wad should
+be rejected (but it don't think it is in practice--TBF).
+Otherwise, this field should not be greater than
+<code>INT_MAX</code>.
+
+<p>The next 4 bytes contain the offset in the wad as an <a
+href="#i32"><code>i32</code></a>. There is no particular
+constraint or checking on this number, although it would be a
+good idea to check that the offset is not negative and does not
+go beyond the end of the wad.
+
+		<h3>Output</h3>
+
+All generated iwads and pwads start with either
+"<code>IWAD</code>" or "<code>PWAD</code>".
+
+	<h2>Wad directory</h2>
+
+		<h3>Input</h3>
+
+<p>The lump names can contain any combination of 8 characters,
+including control characters, though non-printable characters
+will probably make Yadex display garbage, as they are not
+filtered. A NUL terminates the lump name. All characters
+following the NUL are ignored for comparison purposes. The lump
+names are treated in a case-insensitive fashion. That is, any
+lower case alphabetic character of the US-ASCII set (a-z) is
+equivalent to the corresponding upper case character (A-Z) for
+comparison purposes. Alphabetic characters not belonging to the
+US-ASCII set (E.G. accented characters from ISO-8859 or IBM CP
+    437) are <em>not</em> subject to case folding. (Note: in
+practice, I think there are areas where comparisons are
+case-sensitive. TBF.)
+
+		<h3>Output</h3>
+
+<p>The directory and the header never overlap. Depending on the
+function that created the wad, the directory is either between
+the header and the first lump or after the last lump.
+
+<p>Lump names in the output may have their case folded to upper
+case and the tail of the name may be filled with NULs.
+
+	<h2>Levels</h2>
+
+		<h3>Input</h3>
+
+<p>The offset and length of the label are ignored. I'm pretty
+sure Doom ignores them because there are pwads out there that
+have level labels with non-zero lengths and weird offsets.
+
+<p>If the length of a lump is not a multiple of the size of the
+type of object it contains, a warning is printed and the number
+of bytes read is equal to the size truncated to the nearest
+multiple of the object size.
+
+		<h3>Output</h3>
+
+<p>In a wad, a level is formed of 11 lumps, always in the same
+order&nbsp;: the label, <code>THINGS</code>,
+<code>LINEDEFS</code>, <code>SIDEDEFS</code>,
+<code>VERTEXES</code>, <code>SEGS</code>, <code>SSECTORS</code>,
+<code>NODES</code>, <code>SECTORS</code>, <code>REJECT</code>
+and <code>BLOCKMAP</code>.
+
+<p>The label can have any name at the user's discretion (all
+letters are uppercased, though), but in practice it is generally
+either "<code>E<var>n</var>M<var>m</var></code>" or
+"<code>MAP<var>nm</var></code>". The offset of the label is
+always set to the offset of the first lump of the level (that
+is, <code>THINGS</code>). Its length is always 0.
+
+<p>All 10 following directory entries are always present, even
+if the corresponding lumps do not exist. For example, in the
+case of a new level that hasn't had its nodes built, the
+directory entries <code>SEGS</code>, <code>SSECTORS</code> and
+<code>NODES</code> are present, with an offset of 0 and a length
+of 0.
+
+<p><hr>AYM $SELF_DATE
+</body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/docsrc/yadex.6	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,374 @@
+.TH YADEX 6 $SOURCE_DATE "Yadex $VERSION" \" -*- nroff -*-
+.\" .OP - synopsis of an option
+.\"   $1: short name
+.\"   $2: long name
+.\"   $3: argument
+.de OP
+\\fB\-\\$1\\fP, \\fB\-\\$2\\fP \\fI\\$3\\fP
+..
+.SH NAME
+yadex \- a Doom/Heretic/Strife level editor
+.SH SYNOPSIS
+.BR "yadex \-?" | \-help | \-\-help
+.br
+.B yadex \-\-version
+.br
+\fByadex\fP [\fIoptions\fP] [\fIfile\fP ...]
+.br
+\fByadex\fP [\fIoptions\fP] \fB\-b\fP \fIstring\fP [\fIfile\fP ...]
+.SH DESCRIPTION
+Yadex can be used to view, create and modify levels for
+\fBDoom\fP, \fBUltimate Doom\fP, \fBDoom II\fP, \fBFinal
+Doom\fP, \fBDoom press release pre beta\fP and \fBHeretic\fP.
+It also supports, to a lesser extent, \fBDoom alpha\fP,
+\fBHexen\fP and \fBStrife\fP.
+
+See \fBREADME\fP for a quick start.
+.br
+To know what's new in this release, see \fBCHANGES\fP.
+.br
+The rest of documentation is in \fBdoc/index.html\fP (HTML format).
+.SH OPTIONS
+Boolean options can be negated by using \fB+\fP instead of
+\fB\-\fP.  For example, \fB+v\fP would disable verbose mode even
+if \fBverbose\fP is set to 1 in the configuration file. For non
+boolean options, \fB+\fP is equivalent to \fB\-\fP (note: the
+fact that a misimplementation is documented should not be
+construed as an incitement to make use of it).
+
+For options that take a parameter, the option and the parameter
+must be in separate command\-line arguments, i.e. you
+\fIcannot\fP write \fB\-gdoom\fP.
+
+It is not possible to run options together, i.e. you \fIcan't\fP
+use \fB\-dv\fP as short for \fB\-d\fP \fB\-v\fP.
+
+The \fB\-\-\fP "end-of-options" convention is not supported.
+.TP
+.BR \-? , \ \-help , \ \-\-help
+Print usage summary to stdout and exit successfully.
+.TP
+.BI \-b \ string
+Run a benchmark on some part of Yadex and exit successfully. See
+the \fBbenchmark()\fP function for further details.
+.TP
+.OP d debug
+Debug mode.
+This option is equivalent to and overrides the \fBdebug\fP
+directive of the configuration file.
+.TP
+.B \-expert
+Expert mode. Enforces default choices for certain dialogs. As
+those default choices are IMHO not all judicious, I don't
+recommend using this option. Check
+\fBinsert_vertex_split_linedef\fP and
+\fBinsert_vertex_merge_vertices\fP instead.
+This option is equivalent to and overrides the \fBexpert\fP
+directive of the configuration file.
+.TP
+.OP f config_file file
+Use \fIfile\fP as the config file instead of the default.
+.TP
+.OP fc fake_cursor
+(X11 only) Fake cursor. Currently, this option is a no\-op.
+This option is equivalent to and overrides the \fBfake_cursor\fP
+directive of the configuration file.
+.TP
+.OP fn font string
+(X11 only) Use font \fIstring\fP.
+If no font is specified or if the specified font is not
+found, Yadex falls back on the default font of the X server.
+This option is equivalent to and overrides the \fBfont\fP
+directive of the configuration file.
+.TP
+.OP g game string
+Set the game to \fIstring\fP, which can be one of the following:
+.if n \{ .ta 2 12
+.sp \}
+.if t \{ .ta 1.5 7.5
+.sp 0.4 \}
+.nf
+\(bu	\fBdoom\fP	Doom or Ultimate Doom
+\(bu	\fBdoom02\fP	Doom alpha 0.2
+\(bu	\fBdoom04\fP	Doom alpha 0.4
+\(bu	\fBdoom05\fP	Doom alpha 0.5
+\(bu	\fBdoom2\fP	Doom II or Final Doom
+\(bu	\fBdoompr\fP	Doom press release pre-beta
+\(bu	\fBheretic\fP	Heretic
+\(bu	\fBhexen\fP	Hexen
+\(bu	\fBstrife\fP	Strife 1.1 and later
+\(bu	\fBstrife10\fP	Strife 1.0
+.fi
+.if n .sp
+.if t .sp 0.4
+This option is equivalent to and overrides the \fBgame\fP
+directive of the configuration file.
+.TP
+.OP h height integer
+(X11 only) Initial height of the window. If the argument is just
+a number, the height of the window will be that many pixels. If
+the argument is a number followed by a percent sign (\fB%\fP),
+it will be that many percent of the width of the screen. The
+default is 90%.
+This option is equivalent to and overrides the \fBheight\fP
+directive of the configuration file.
+See also \fB\-w\fP.
+.TP
+.OP i1 iwad1 file
+The name of the Doom or Ultimate Doom iwad.
+This option has effect only if the game is \fBdoom\fP.
+This option is equivalent to and overrides the \fBiwad1\fP
+directive of the configuration file.
+.TP
+.OP i2 iwad2 file
+The name of the Doom II or Final Doom iwad.
+This option has effect only if the game is \fBdoom2\fP.
+This option is equivalent to and overrides the \fBiwad2\fP
+directive of the configuration file.
+.TP
+.OP i3 iwad3 file
+The name of the Heretic iwad.
+This option has effect only if the game is \fBheretic\fP.
+This option is equivalent to and overrides the \fBiwad3\fP
+directive of the configuration file.
+.TP
+.OP i4 iwad4 file
+The name of the Hexen iwad.
+This option has effect only if the game is \fBhexen\fP.
+This option is equivalent to and overrides the \fBiwad4\fP
+directive of the configuration file.
+.TP
+.OP i5 iwad5 file
+The name of the Strife iwad.
+This option has effect only if the game is \fBstrife\fP.
+This option is equivalent to and overrides the \fBiwad5\fP
+directive of the configuration file.
+.TP
+.OP i6 iwad6 file
+The name of the Doom alpha 0.2 iwad.
+This option has effect only if the game is \fBdoom02\fP.
+This option is equivalent to and overrides the \fBiwad6\fP
+directive of the configuration file.
+.TP
+.OP i7 iwad7 file
+The name of the Doom alpha 0.4 iwad.
+This option has effect only if the game is \fBdoom04\fP.
+This option is equivalent to and overrides the \fBiwad7\fP
+directive of the configuration file.
+.TP
+.OP i8 iwad8 file
+The name of the Doom alpha 0.5 iwad.
+This option has effect only if the game is \fBdoom05\fP.
+This option is equivalent to and overrides the \fBiwad8\fP
+directive of the configuration file.
+.TP
+.OP i9 iwad9 file
+The name of the Doom press release pre-beta iwad.
+This option has effect only if the game is \fBdoompr\fP.
+This option is equivalent to and overrides the \fBiwad9\fP
+directive of the configuration file.
+.TP
+.OP i10 iwad10 file
+The name of the Strife 1.0 iwad.
+This option has effect only if the game is \fBstrife10\fP.
+This option is equivalent to and overrides the \fBiwad10\fP
+directive of the configuration file.
+.TP
+.OP pw pwad file
+[Deprecated] Load pwad \fIfile\fP. This option is useless since
+pwads can be given as arguments anyway. It's there for backward
+compatibility only.
+This option is equivalent to and overrides the \fBpwad\fP
+directive of the configuration file.
+.TP
+.OP P no_pixmap
+(X11 only) Use no pixmap. Makes Yadex more responsive at the
+cost of a lot of flickering. Off by default.
+This option is equivalent to and overrides the \fBno_pixmap\fP
+directive of the configuration file.
+.TP
+.OP q quiet
+In theory, quiet mode. In practice, has no effect.
+This option is equivalent to and overrides the \fBquiet\fP
+directive of the configuration file.
+.TP
+.OP qq quieter
+Quieter. Makes Yadex completely silent (beepless).
+This option is equivalent to and overrides the \fBquieter\fP
+directive of the configuration file.
+.TP
+.OP s0 select0
+Select the 0th object automatically whenever the editing mode is
+set.
+This option is equivalent to and overrides the \fBselect0\fP
+directive of the configuration file.
+.TP
+.OP sb swap_buttons
+Swap mouse buttons. Currently, this option is a no\-op.
+This option is equivalent to and overrides the \fBswap_buttons\fP
+directive of the configuration file.
+.TP
+.OP td text_dot
+Debug the \fBDrawScreenText\fP() function.
+This option is equivalent to and overrides the \fBtext_dot\fP
+directive of the configuration file.
+.TP
+.OP v verbose
+Verbose mode.
+This option is equivalent to and overrides the \fBverbose\fP
+directive of the configuration file.
+.TP
+.B \-\-version
+Print version information to stdout and exit successfully.
+
+The first line contain three fields, separated by white space,
+with no other punctuation. The first field is the name of the
+program ("\fBYadex\fP"). The second field is the version number
+("\fB$VERSION\fP"). The third field is the release date, between
+parentheses ("\fB($SOURCE_DATE)\fP").
+
+The second line contains a configuration file magic string (not
+used).
+
+The third line contains the magic string that this version
+requires at the beginning of game definition files.
+.TP
+.OP w width dimension
+(X11 only) Initial width of the window. If the argument is just
+a number, the width of the window will be that many pixels. If
+the argument is a number followed by a percent sign (\fB%\fP),
+it will be that many percent of the width of the screen. The
+default is 90%.
+This option is equivalent to and overrides the \fBwidth\fP
+directive in the configuration file.
+See also \fB\-h\fP.
+.TP
+.OP z zoom_default integer
+Initial zoom factor in percent. The default is 0, which means
+that the zoom factor is to be adjusted so that the level fills
+the window.
+This option is equivalent to and overrides the \fBzoom_default\fP
+directive of the configuration file.
+.SH FILES
+.SS Configuration files
+.nf
+$FILES_ETC
+.fi
+.SS Game definition files
+.nf
+$FILES_SHARE
+.fi
+.SS Swap files
+.B $TMPDIR/yadexswp??????
+.br
+.B /tmp/yadexswp??????
+.SH ENVIRONMENT VARIABLES
+.IP \fBDISPLAY\fP
+X11 only. The name of the X display that Yadex will try to
+connect to.
+.IP \fBHOME\fP
+Used to expand \fB~\fP when locating configuration and game
+definition files.
+.IP \fBLINES\fP
+If set, Yadex assumes the tty has that many lines instead of 24.
+The value must be an unsigned, non-zero decimal integer.
+.IP \fBTMPDIR\fP
+If set, swap files are created there. Otherwise, in \fB/tmp\fP.
+.IP \fBYADEX_GAME\fP
+Indicates the game to use. Overrides the \fBgame\fP parameter in
+the config file, is overridden by the \fB\-g\fP command line
+option.
+.SH APPLICATION RESOURCES
+None. Yadex does not use the X resources system.
+.SH EXIT STATUS
+.ta 3
+\fB0\fP	OK.
+.br
+\fB1\fP	Incorrect invocation.
+.br
+\fB>1\fP	Fatal error.
+.SH BUGS
+In certain circumstances, exposures are not handled.
+If the Yadex window turns black,
+back out by pressing [Esc], several times if necessary.
+
+If you edit a level from a file that contains several and save it,
+all the other levels from that file are lost.
+
+And many more. See \fBTODO\fP.
+.SH AUTHOR
+André Majorel (http://www.teaser.fr/~amajorel/)
+
+.nf
+Contributors:
+Andrew J. Apted (http://www.netspace.net.au/~ajapted/)
+Matthew W. Miller (zbp+ee+fhozhybp=eryyvzjz)
+.fi
+
+Yadex is derived from DEU 5.21 that was written by Raphaël Quinet,
+Brendon Wyber and others.
+
+See the HTML documentation for detailed credits.
+.SH LEGAL
+.SS Yadex
+.nf
+$COPYRIGHT_MAN
+.fi
+
+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 Library General Public
+License along with this library; if not, write to the Free
+Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307, USA.
+.SS Atclib
+The Yadex distribution includes a subset of Atclib.
+
+Atclib is copyright André Majorel 1995-1999 and distributed under the terms of
+version 2 of the GNU Library General Public License.
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of version 2 of the GNU Library General Public
+License as published by the Free Software Foundation.
+
+This library 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with this library; if not, write to the Free
+Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+MA 02111-1307, USA
+.SS Boost
+The Yadex distribution includes a subset of Boost 1.25.0.
+
+Boost 1.25.0 is copyright various authors and released under the following
+terms\ : Permission to copy, use, modify, sell and distribute this software is
+granted provided this copyright notice appears in all copies.
+This software is provided "as is" without express or implied warranty, and with
+no claim as to its suitability for any purpose.
+.SH SEE ALSO
+.BR bsp (6),
+.BR idbsp (6),
+.BR tkwadcad (6),
+.BR warm (6),
+.BR xwadtools (6)
+.IP LDE
+http://interreality.org/~tetron/technology/lde/
+.IP PFME
+http://www.purplefrog.com/~thoth/purplefrog/editor.html
+.IP Why
+http://www.hut.fi/~jpakkane/why/
+.IP "Xwad (part of Dumb)"
+http://stekt.oulu.fi/~tosi/dumb/dumb.html
+.IP Xwadtools
+ftp://3darchives.in-span.net/pub/idgames/source/
Binary file docsrc/yadex1.png has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/docsrc/ygd.html	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,487 @@
+<html>
+<head>
+  <title>Yadex game definition files</title>
+  <style type="text/css">
+    var {
+      font-style: normal;
+      font-weight: normal;
+      text-decoration: underline;
+    }
+  </style>
+</head>
+<body>
+
+<div align="center">
+<img src="logo_small.png" alt="Fancy logo">
+<br>Yadex $VERSION ($SOURCE_DATE)
+<h1>Yadex game definition files</h1>
+</div>
+<br>
+<br>
+<br>
+
+	<h2>Introduction</h2>
+
+<p>Yadex game definition files (conventional extension
+<code>.ygd</code>) are designed to contain all the information
+relative to a particular game. The syntax and the semantics are
+very simple&nbsp;; it's more like a database than a real script
+language. For normal use, you don't ever need to read, much less
+modify, ygd files.
+
+	<h2>General syntax</h2>
+
+<p>A file is a valid Yadex game definition file if its first
+line contains exactly the following magic string&nbsp;:
+"<code>#&nbsp;Yadex&nbsp;game&nbsp;definition&nbsp;file&nbsp;version&nbsp;4</code>"
+(without the double quotes).
+
+<p>The rest of the file is split in lines, each line separated
+from the following by a newline. White space at the beginning
+and end of a line is stripped. Each line is then split in
+tokens, separated by one or more white space characters. A
+double quote removes the special meaning of subsequent
+white space characters until the next double quote. A token
+formed of just two consecutive double quotes is an empty
+token&nbsp;: its value is the empty string. Double quotes are
+stripped from the token after the token splitting is done. There
+is no way to include a double quote in the contents of a token.
+
+<p>A hash mark ("<code>#</code>") at the beginning of a token
+marks the beginning of a comment. Everything from the hash to
+the end of the line is stripped. If no tokens remain, the line
+is ignored. If at least one token remains, the first token must
+be the name of a valid directive and the following form its
+arguments. If the first token is not the name of a valid
+directive or the number of arguments is wrong, the whole file is
+rejected.
+
+<p>Note that the following common features are <em>not</em>
+supported&nbsp;: breaking lines with "<code>;</code>", joining
+lines with "<code>\</code>" at the end of the first line,
+quoting with "<code>'</code>" or "<code>\</code>".
+
+<p>The following lines are equivalent&nbsp;:
+<pre>foo bar baz
+foo bar baz      # You too can wear a nose mitten
+foo bar  baz
+foo "bar" baz
+foo bar "b""a""z"""
+foo bar ba""z
+  foo bar baz</pre>
+
+<p>The following lines are <em>not</em> equivalent to the above&nbsp;:
+<pre>foo bar baz ""
+foo bar "baz "
+</pre>
+
+	<h2>Directives</h2>
+
+<dl>
+<p><dt><h3><code><strong>ldt</strong>
+		<var>type</var>
+		<var>group</var>
+		<var>shortdesc</var>
+		<var>longdesc</var></code></h3></p>
+
+<p><dd>Defines a linedef type. Takes exactly 4 arguments.</p>
+
+  <p><table>
+    <tr valign="top">
+      <td><code><var>type</var></code>
+      <td>&nbsp;
+      <td>The linedef type. Must be a decimal integer.
+
+    <tr valign="top">
+      <td><code><var>group</var></code>
+      <td>&nbsp;
+      <td>The linedef type group this linedef type belongs to.
+	This field is silently truncated to 1 character. The
+	group must have been prealably defined by an
+	<code>ldtgroup</code> directive.
+
+    <tr valign="top">
+      <td><code><var>shortdesc</var></code> 
+      <td>&nbsp;
+      <td>Description that will be displayed in the object info
+	window. There is no limit on the length of this field
+	but only the first 16 characters of it are shown in the
+	object info window.
+
+    <tr valign="top">
+      <td><code><var>longdesc</var></code>
+      <td>&nbsp;
+      <td>Description that will be displayed everywhere else.
+	There is no precise limit on the length of this field
+	but it's recommended to keep it within reasonable
+	limits.
+  </table></p>
+
+  <p>There should be at least one linedef type for each group
+    defined. There is no precise upper limit but defining more
+    than 30 in the same group will cause problems. You should
+    not define the same linedef type more than once.</p>
+
+<br>
+
+<p><dt><h3><code><strong>ldtgroup</strong>
+		<var>group</var>
+		<var>desc</var></code></h3></p>
+
+<p><dd>Defines a group of linedef types. Takes exactly 2
+  arguments.</p>
+
+  <p><table>
+    <tr valign="top">
+      <td><code><var>group</var></code>
+      <td>&nbsp;
+      <td>The identifier of the linedef types group. It is
+	silenty truncated to 1 character.
+
+    <tr valign="top">
+      <td><code><var>desc</var></code>
+      <td>&nbsp;
+      <td>Description. There is no precise limit on the length
+	of the this field but it's recommended to keep it within
+	reasonable limits.
+  </table></p>
+
+  <p>There is no upper or lower limit on the number of groups
+    but defining more than 20 will cause problems. You should
+    not define the same group more than once.</p>
+
+<br>
+
+<p><dt><h3><code><strong>level_format</strong>
+		<var>level_format</var></code></h3></p>
+
+<p><dd>Indicates the format in which levels are stored in the
+  wad. There is only one argument. It can have the following
+  values&nbsp;:</p>
+
+  <p><table border>
+  <tr>
+    <th>Value
+    <th>Meaning
+  <tr>
+    <td valign="top"><code>alpha</code>
+    <td>Doom alpha format, 7 directory entries per level (label,
+    <code>FLATNAME</code>, <code>POINTS</code>,
+    <code>LINES</code>, <code>SECTORS</code> and
+    <code>THINGS</code>).
+  <tr>
+    <td valign="top"><code>doom</code>
+    <td>Normal Doom format, 11 directory entries per level (label,
+    <code>THINGS</code>, <code>LINEDEFS</code>,
+    <code>SIDEDEFS</code>, <code>VERTEXES</code>,
+    <code>SEGS</code>, <code>SSECTORS</code>, <code>NODES</code>,
+    <code>SECTORS</code>, <code>REJECT</code> and
+    <code>BLOCKMAP</code>).
+  <tr>
+    <td valign="top"><code>hexen</code>
+    <td>Hexen format, 12 directory entries per level (same as for
+    <code>doom</code> then <code>BEHAVIOR</code>).
+  </table></p>
+
+  <p>Reading is supported for all formats but writing is not
+  supported for <code>hexen</code>. For <code>alpha</code>,
+  writing is done in <code>doom</code> format.</p>
+
+  <p>This directive is mandatory. If there are several
+  <code>level_format</code> directives, it's the last one that
+  counts.</p>
+
+  <br>
+
+<p><dt><h3><code><strong>level_name</strong>
+		<var>level_name</var></code></h3></p>
+
+<p><dd>Indicates whether the level names for that game are of
+the form <code>E<var>n</var>M<var>n</var></code> or of the form
+<code>MAP<var>nm</var></code>. There is only one argument. It
+can have the following values&nbsp;:</p>
+
+  <p><table border>
+  <tr>
+    <th>Value
+    <th>Meaning
+  <tr>
+    <td valign="top"><code>e1m1</code>
+    <td><code>E<var>n</var>M<var>m</var></code> (Doom, Doom
+    press release and Heretic).
+  <tr>
+    <td valign="top"><code>e1m10</code>
+    <td><code>E<var>n</var>M<var>m</var></code> or
+    <code>E<var>i</var>M<var>jk</var></code> (Doom alpha only)
+  <tr>
+    <td valign="top"><code>map01</code>
+    <td><code>MAP<var>nm</var></code> (Doom II, Hexen and
+    Strife).
+  </table></p>
+
+  <p>The influence of this directive on the behaviour of Yadex is
+  in the choice of the default name for new levels and the way
+  shorthand arguments to the <code>edit</code> and
+  <code>create</code> commands are interpreted.</p>
+
+  <p>This directive is mandatory. If there are several
+  <code>level_name</code> directives, it's the last one that
+  counts.</p>
+
+<br>
+
+<p><dt><h3><code><strong>picture_format</strong>
+		<var>picture_format</var></code></h3></p>
+
+<p><dd>Indicates in which format the pictures are stored in the
+  wads. There is only one argument. It can have the following
+  values&nbsp;:</p>
+
+  <p><table border>
+  <tr>
+    <th>Value
+    <th>Meaning
+  <tr>
+    <td valign="top"><code>alpha</code>
+    <td>The obsolete format used in Doom alpha 0.2, 0.4 and 0.5.
+  <tr>
+    <td valign="top"><code>pr</code>
+    <td>The obsolete format used in the Doom press release pre-beta.
+  <tr>
+    <td valign="top"><code>normal</code>
+    <td>The normal format used by all other iwads.
+  </table></p>
+
+  <p>This directive is optional. If it's missing, the default is
+  <code>normal</code>. If it's repeated, it's the last occurrence
+  that counts.</p>
+
+<br>
+
+<p><dt><h3><code><strong>sky_flat</strong>
+		<var>flat_name</var></code></h3></p>
+
+<p><dd>Specifies the name of the flat used for skies. This is
+    important to Yadex as far as upper and lower texture
+    checking is concerned (upper/lower textures are not rendered
+    if both sectors have a sky ceiling/floor). The argument is
+    matched against the sector's flat name in a case-insensitive
+    fashion where at most the 8 first characters matter. I
+    personally use lower case and recommend that you follow the
+    same convention.</p>
+
+  <p>This directive is optional. If it's missing, all flats will
+    be considered normal. If it's repeated, it's the last
+    occurrence that counts.</p>
+
+<br>
+
+<p><dt><h3><code><strong>st</strong>
+		<var>type</var>
+		<var>shortdesc</var>
+		<var>longdesc</var></code></h3></p>
+
+<p><dd>Defines a sector type. Takes exactly 3 arguments</p>
+
+  <p><table>
+    <tr valign="top">
+      <td><code><var>type</var></code>
+      <td>&nbsp;
+      <td>Must be a decimal integer.
+      
+    <tr valign="top">
+      <td><code><var>shortdesc</var></code>
+      <td>&nbsp;
+      <td>Short description that will be displayed in the object
+	info window. There is no limit on the length of the
+	short description but only the first 14 characters are
+	shown in the object info window.
+
+    <tr valign="top">
+      <td><code><var>longdesc</var></code>
+      <td>&nbsp;
+      <td>Long description that will be displayed everywhere
+	else. There is no precise limit on the length of this
+	field but it's recommended to keep it within
+	reasonable limits.
+  </table></p>
+
+  <p>There is no lower limit on the number of <code>st</code>
+  directives. If there are too many of them, the menu will not
+  fit in the window so don't do that. You should not define the
+  same sector type more than once.</p>
+
+<br>
+
+<p><dt><h3><code><strong>texture_format</strong>
+		<var>texture_format</var></code></h3></p>
+
+<p><dd>Indicates in which format the textures are stored in the
+  wads. There is only one argument. It can have the following
+  values&nbsp;:</p>
+
+  <p><table border>
+  <tr>
+    <th>Value
+    <th>Meaning
+  <tr>
+    <td valign="top"><code>nameless</code>
+    <td>The obsolete format used in Doom alpha 0.4 (no texture
+    names).
+  <tr>
+    <td valign="top"><code>strife11</code>
+    <td>The format used by Strife 1.1 and later. Note that
+    Strife 1.0 uses the regular format (<code>normal</code>).
+  <tr>
+    <td valign="top"><code>normal</code>
+    <td>The normal format used by all other iwads.
+  </table></p>
+
+  <p>This directive is optional. If it's missing, the default is
+    <code>normal</code>. If it's repeated, it's the last
+    occurrence that counts.</p>
+ 
+<br>
+
+<p><dt><h3><code><strong>texture_lumps</strong>
+		<var>texture_lumps</var></code></h3></p>
+
+<p><dd>Indicates in which lump(s) is the list of textures for
+  that game. There is only one argument. It can have the
+  following values&nbsp;:</p>
+
+  <p><table border>
+  <tr>
+    <th>Value
+    <th>Meaning
+  <tr>
+    <td valign="top"><code>textures</code>
+    <td>There is only one lump and it's called
+    <code>TEXTURES</code> (Doom alpha 0.4 and 0.5).
+  <tr>
+     <td valign="top"><code>none</code>
+     <td>There is no textures lump (Doom alpha 0.2)
+  <tr>
+    <td valign="top"><code>normal</code>
+    <td>There is <code>TEXTURE1</code> and optionally
+    <code>TEXTURE2</code> (all other iwads).
+  </table></p>
+
+  <p>This directive is optional. If it's missing, the default is
+    <code>normal</code>. If it's repeated, it's the last
+    occurrence that counts.</p>
+
+<br>
+
+<p><dt><h3><code><strong>thing</strong>
+		<var>type</var>
+		<var>group</var>
+		<var>flags</var>
+		<var>radius</var>
+		<var>desc</var>
+		</code>[<code><var>sprite</var></code>]</h3></p>
+
+<p><dd>Defines a thing type. Takes 5 or 6 arguments.</p>
+
+  <p><table>
+    <tr valign="top">
+      <td><code><var>type</var></code>
+      <td>&nbsp;
+      <td>Must be a decimal integer.
+
+    <tr valign="top">
+      <td><code><var>group</var></code>
+      <td>&nbsp;
+      <td>The thing type group this thing type belongs to. This
+	field is silently truncated to 1 character. The group
+	must have been prealably defined by a
+	<code>thinggroup</code> directive.
+
+    <tr valign="top">
+      <td><code><var>flags</var></code>
+      <td>&nbsp;
+      <td>Should be either "<code>s</code>" for things that have
+	a spectral or translucent look (like Doom's spectres and
+	Heretic's ghosts) or "<code>-</code>" for the others.
+
+    <tr valign="top">
+      <td><code><var>radius</var></code>
+      <td>&nbsp;
+      <td>Radius. Must be a strictly positive integer.
+
+    <tr valign="top">
+      <td><code><var>desc</var></code>
+      <td>&nbsp;
+      <td>Description. There is not
+	limit on the length of this field but only the first 19
+	characters of it are shown in the object info window.
+
+    <tr valign="top">
+      <td><code><var>sprite</var></code>
+      <td>&nbsp;
+      <td>The root of the name of the sprite associated with
+	the thing type. Yadex will display the first (in
+	alphabetical order) sprite whose name begins with those
+	characters. For example, if the root is
+	<code>CEYE</code> and the iwad contains sprites
+	<code>CEYEA0</code>, <code>CEYEB0</code> and
+	<code>CEYEC0</code>, the sprite displayed will be
+	<code>CEYEA0</code>. If this field is omitted, Yadex
+	will show no sprite for this thing type. This is
+	appropriate for things that have no visual
+	representation, like sound sources. The present
+	convention is to use upper case (and I've not tested
+	whether lower case works).
+
+  </table></p>
+
+  <p>There should be at least one thing type for each thing type
+    group defined. There is no precise upper limit but defining
+    more than 30 thing types in the same group will cause
+    problems. You should not define the same thing type more
+    than once.</p>
+
+<br>
+
+<p><dt><h3><code><strong>thinggroup</strong>
+		<var>group</var>
+		<var>colour</var>
+		<var>desc</var></code></h3></p>
+
+<p><dd>Defines a group of thing types. Takes exactly 3 arguments.</p>
+
+  <p><table>
+    <tr valign="top">
+      <td><code><var>group</var></code>
+      <td>&nbsp;
+      <td>The identifier of the thing types group. It is silenty
+	truncated to 1 character.
+
+    <tr valign="top">
+      <td><code><var>colour</var></code>
+      <td>&nbsp;
+      <td>The colour in which things pertaining to this group
+	will be displayed the editing window. It's an X11-style
+	colour specification. The syntax is
+	"<code>rgb:<var>r</var>/<var>g</var>/<var>b</var></code>"
+	where <code><var>r</var></code>,
+	<code><var>g</var></code> and <code><var>b</var></code>
+	are each one or more hexadecimal digits.
+
+    <tr valign="top">
+      <td><code><var>desc</var></code>
+      <td>&nbsp;
+      <td>Description. There is no precise limit on the length
+	of the this field but it's recommended to keep it within
+	reasonable limits.
+  </table></p>
+
+  <p>There is no upper or lower limit on the number of groups
+    but defining more than 20 will cause problems. You should
+    not define the same group more than once.</p>
+
+</dl>
+
+<p><hr>AYM $SELF_DATE
+</body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/patches/1.5.0_gcc27.diff	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,240 @@
+yadex-1.5.0_gcc-2.7.diff - make compile Yadex 1.5.0 with GCC 2.7
+
+To apply,
+
+  cd yadex-1.5.0
+  patch -p1 <patch/gcc-2.7.diff
+
+GCC 2.7 is not recommended to compile C++. It's shipped with a
+very old version of STL, hence conflict on "times" and missing
+clear(). It insists on having default constructors for classes
+used in conjunction with the STL containers. It wants three
+arguments for map<>. It barfs if you use -> on the right hand
+of an iterator. It's a pain.
+
+I consider GCC 2.7 obsolete, and not a supported compiler for
+Yadex. This patch will rot or go away. Please upgrade. More
+recent versions of EGCS and GCC work fine.
+
+-- AYM 2000-08-27
+
+diff -ur yadex-1.5.0/src/bench.cc yadex-1.5.0-gcc27/src/bench.cc
+--- yadex-1.5.0/src/bench.cc	Sun Aug 13 16:43:11 2000
++++ yadex-1.5.0-gcc27/src/bench.cc	Sun Aug 27 17:41:26 2000
+@@ -33,10 +33,12 @@
+ #include <time.h>
+ #include <sys/times.h>
+ 
++#define times FOOBAR
+ #include "gfx.h"
+ #include "img.h"
+ #include "pic2img.h"
+ #include "wadres.h"
++#undef times
+ 
+ 
+ 
+diff -ur yadex-1.5.0/src/drawmap.cc yadex-1.5.0-gcc27/src/drawmap.cc
+--- yadex-1.5.0/src/drawmap.cc	Thu Aug 24 15:36:36 2000
++++ yadex-1.5.0-gcc27/src/drawmap.cc	Sun Aug 27 18:03:49 2000
+@@ -518,6 +518,7 @@
+ class Thing_npixels
+ {
+   public :
++    Thing_npixels () : thing_no (0), npixels (0), type (0) { }
+     Thing_npixels (i16 thing_no, unsigned long npixels, wad_ttype_t type)
+       : thing_no (thing_no), npixels (npixels), type (type) { }
+     bool operator< (const Thing_npixels& other) const
+@@ -541,7 +542,7 @@
+     const Thing_npixels& operator[] (int n) { return a[n]; }
+     void refresh ()
+     {
+-      a.clear ();
++      a.erase (a.begin (), a.end ());
+       a.reserve (NumThings);
+       for (int n = 0; n < NumThings; n++)
+       {
+@@ -576,7 +577,20 @@
+   unsigned short height;
+ };
+ 
+-typedef map <i16, sprite_dim_t> dim_map_t;
++class Dim_map_key
++{
++  public :
++    Dim_map_key () { value = 0; }
++    Dim_map_key (i16 v) { value = v; }
++    i16 value;
++};
++
++bool operator< (Dim_map_key a, Dim_map_key b)
++{
++  return a.value - b.value;
++}
++
++typedef map <Dim_map_key, sprite_dim_t, less<Dim_map_key> > dim_map_t;
+ static dim_map_t dim_map;  // FIXME there should be one for each game
+ 
+ 
+@@ -638,10 +652,10 @@
+       }
+       else
+       {
+-	mapx0 = MAPX (0)       - dim->second.width / 2;
+-	mapx9 = MAPX (ScrMaxX) + dim->second.width / 2;
+-	mapy0 = MAPY (ScrMaxY) - dim->second.height / 2;
+-	mapy9 = MAPY (0)       + dim->second.height / 2;
++	mapx0 = MAPX (0)       - (*dim).second.width / 2;
++	mapx9 = MAPX (ScrMaxX) + (*dim).second.width / 2;
++	mapy0 = MAPY (ScrMaxY) - (*dim).second.height / 2;
++	mapy9 = MAPY (0)       + (*dim).second.height / 2;
+       }
+     }
+     int mapx = Things[t.thing_no].xpos;
+diff -ur yadex-1.5.0/src/lumpdir.cc yadex-1.5.0-gcc27/src/lumpdir.cc
+--- yadex-1.5.0/src/lumpdir.cc	Mon Jun  5 13:46:40 2000
++++ yadex-1.5.0-gcc27/src/lumpdir.cc	Sun Aug 27 17:38:44 2000
+@@ -64,7 +64,7 @@
+   if (dependency)
+     delete dependency;
+   if (! lump_map.empty ())
+-    lump_map.clear ();
++    lump_map.erase (lump_map.begin (), lump_map.end ());
+ }
+ 
+ 
+@@ -92,7 +92,7 @@
+   if (i == lump_map.end ())
+     loc.wad = loc_prev.wad = 0;
+   else
+-    loc = loc_prev = i->second;
++    loc = loc_prev = (*i).second;
+ }
+ 
+ 
+@@ -122,7 +122,7 @@
+      And usually is ! */
+   have_prev = false;
+   if (! lump_map.empty ())
+-    lump_map.clear ();
++    lump_map.erase (lump_map.begin (), lump_map.end ());
+ 
+   /* Get list of lumps in the master directory. Everything
+      that is between X_START/X_END or XX_START/XX_END and that
+@@ -231,7 +231,8 @@
+   {
+     array[n] = new char[WAD_NAME + 1];
+     *array[n] = '\0';
+-    strncat (array[n], i++->first.name, WAD_NAME);
++    strncat (array[n], (*i).first.name, WAD_NAME);
++    i++;
+   }
+ }
+ 
+diff -ur yadex-1.5.0/src/lumpdir.h yadex-1.5.0-gcc27/src/lumpdir.h
+--- yadex-1.5.0/src/lumpdir.h	Thu Jun  1 14:25:30 2000
++++ yadex-1.5.0-gcc27/src/lumpdir.h	Sun Aug 27 17:38:44 2000
+@@ -34,10 +34,11 @@
+ 
+ #include <map>
+ 
++#include "wadname.h"
++
+ 
+ class Dependency;
+ class Serial_num;
+-class Wad_name;
+ 
+ 
+ /*
+diff -ur yadex-1.5.0/src/objinfo.cc yadex-1.5.0-gcc27/src/objinfo.cc
+--- yadex-1.5.0/src/objinfo.cc	Sat Aug 26 16:22:37 2000
++++ yadex-1.5.0-gcc27/src/objinfo.cc	Sun Aug 27 18:07:51 2000
+@@ -56,6 +56,12 @@
+ class Extraf
+ {
+   public :
++    Extraf ()
++    {
++      sector = 0;
++      memset (tex, '\0', sizeof tex);
++      height = 0;
++    }
+     Extraf (obj_no_t sector, wad_name_t& tex, wad_z_t height)
+     {
+       this->sector = sector;
+@@ -683,7 +689,7 @@
+  */
+ static void get_extrafloors (vector<Extraf>& v, wad_tag_t tag)
+ {
+-  v.clear ();
++  v.erase (v.begin (), v.end ());
+   for (obj_no_t l = 0; l < NumLineDefs; l++)
+   {
+     if (LineDefs[l].tag == tag
+diff -ur yadex-1.5.0/src/patchdir.cc yadex-1.5.0-gcc27/src/patchdir.cc
+--- yadex-1.5.0/src/patchdir.cc	Sat Apr 29 00:57:39 2000
++++ yadex-1.5.0-gcc27/src/patchdir.cc	Sun Aug 27 17:38:44 2000
+@@ -60,7 +60,7 @@
+   if (pnames != 0)
+     FreeMemory (pnames);
+   if (! patch_lumps.empty ())
+-    patch_lumps.clear ();
++    patch_lumps.erase (patch_lumps.begin (), patch_lumps.end ());
+ }
+ 
+ 
+@@ -78,7 +78,7 @@
+     npnames = 0;
+   }
+   if (! patch_lumps.empty ())
+-    patch_lumps.clear ();
++    patch_lumps.erase (patch_lumps.begin (), patch_lumps.end ());
+ 
+   /* First load PNAMES so that we known in which order we should
+      put the patches in the array. */
+@@ -221,7 +221,7 @@
+     loc.wad = 0;
+     return;
+   }
+-  loc = i->second;
++  loc = (*i).second;
+ }
+ 
+ 
+@@ -293,7 +293,8 @@
+   {
+     array[n] = new char[WAD_PIC_NAME + 1];
+     *array[n] = '\0';
+-    strncat (array[n], i++->first._name, WAD_PIC_NAME);
++    strncat (array[n], (*i).first._name, WAD_PIC_NAME);
++    i++;
+   }
+ }
+ 
+diff -ur yadex-1.5.0/src/patchdir.h yadex-1.5.0-gcc27/src/patchdir.h
+--- yadex-1.5.0/src/patchdir.h	Mon Jan 10 13:40:12 2000
++++ yadex-1.5.0-gcc27/src/patchdir.h	Sun Aug 27 17:38:44 2000
+@@ -76,6 +76,7 @@
+ 
+ struct Pllik
+ {
++  Pllik () { memset (_name, '\0', sizeof _name); }
+   Pllik (const char *name);
+   wad_pic_name_t _name;
+ };
+diff -ur yadex-1.5.0/src/spritdir.cc yadex-1.5.0-gcc27/src/spritdir.cc
+--- yadex-1.5.0/src/spritdir.cc	Sun Jul  9 23:04:18 2000
++++ yadex-1.5.0-gcc27/src/spritdir.cc	Sun Aug 27 17:38:44 2000
+@@ -58,9 +58,9 @@
+ 
+   Lump_map::const_iterator i = lump_map.lower_bound (name);
+   have_prev = true;
+-  if (i == lump_map.end () || y_strnicmp (name, i->first.name, strlen (name)))
++  if (i == lump_map.end () || y_strnicmp (name, (*i).first.name, strlen (name)))
+     loc.wad = loc_prev.wad = 0;
+   else
+-    loc = loc_prev = i->second;
++    loc = loc_prev = (*i).second;
+ }
+ 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/patches/README	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,26 @@
+These are patches for Yadex that have for some reason not made
+it in the stable version. Some were written by me, some by
+others.
+
+Please note :
+
+- These patches are not part of the stable version; they come
+  with NO WARRANTY (as if the stable version came with any sort
+  of warranty). They may not have been given even the slightest
+  amount of testing. How long since your last backup ?
+
+- These diffs are against various versions of Yadex, not
+  necessarily the latest one or the one you have. Sometimes a
+  patch against version X works against version Y, sometimes
+  not. While patching, keep an eye open for error messages such
+  as "Hunk #n FAILED".
+
+- To apply, try this :
+
+    $ cd yadex-$VERSION
+    $ patch -p1 <foo.diff
+
+  You may have to tweak the arguments to patch but -p1 should
+  work with most diffs.
+
+-- AYM 2001-07-01
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/copyright	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,177 @@
+#!/usr/bin/perl -w
+#
+#	copyright - print copyright info from docsrc/copyright
+#	AYM 2002-09-15
+#
+
+
+# This file is copyright André Majorel 2002.
+# 
+# This program is free software; you can redistribute it and/or modify it under
+# the terms of version 2 of the GNU General Public License as published by the
+# Free Software Foundation.
+# 
+# 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.
+
+
+use strict;
+use Getopt::Long;
+
+
+sub byname ($$);
+
+
+my %licences =
+(
+  'GPL'  => 'GNU GPL v2', 
+  'LGPL' => 'GNU LGPL v2',
+  'PD'   => 'public domain'
+);
+
+
+my @items;
+my $what = 'copyright';
+my $format = undef;
+
+
+#
+#	Parse the command line
+#
+{
+  Getopt::Long::Configure 'bundling', 'noignorecase';
+  die "copyright: syntax error\n"
+    if ! GetOptions
+      'a' => sub { $what   = 'authors'; },
+      'c' => sub { $format = 'c';       },
+      'h' => sub { $format = 'html';    },
+      'm' => sub { $format = 'troff';   },
+      't' => sub { $format = 'text';    };
+  die "copyright: use one of -chmt\n" if ! defined $format;
+}
+
+
+#
+#	Load the AUTHORS file
+#
+while (defined (my $line = <>))
+{
+  chomp $line;
+  my @fields = split "\t", $line;
+  die "copyright: $ARGV($.): wrong number of fields\n" if (@fields != 4);
+  my %authinfo;
+  $authinfo{name}      = $fields[0];
+  $authinfo{firstname} = $fields[1];
+  $authinfo{years}     = $fields[2];
+  $authinfo{licence}   = $fields[3];
+  push @items, \%authinfo;
+}
+
+
+#
+#	Write the output into @output (one line per element)
+#
+my @output;
+if ($what eq 'authors')		# Print the list of authors
+{
+  foreach my $item (sort byname @items)
+  {
+    push @output, "$item->{firstname} $item->{name}";
+  }
+}
+elsif ($what eq 'copyright')	# Print the list of copyright holders
+{
+  foreach my $item (sort byname @items)
+  {
+    my $licence;
+    die "copyright: bad licence \"$item->{licence}\"\n"
+      if ! exists $licences{$item->{licence}};
+    $licence = $licences{$item->{licence}};
+
+    my $string;
+    if ($item->{licence} eq 'PD')
+    {
+      $string = "Parts written by"
+	. " $item->{firstname} $item->{name}"
+	. ", $licence";
+    }
+    else
+    {
+      $string = "Parts copyright"
+	. " $item->{firstname} $item->{name}"
+	. " $item->{years}"
+	. ", $licence";
+    }
+    push @output, $string;
+  }
+}
+else
+{
+  die "copyright: bad \$what \"$what\"";
+}
+
+
+#
+#	Dump @output to stdout using the specified format
+#	(text, troff, HTML, C)
+#
+if ($format eq 'c')
+{
+  print "\n";
+  print "extern const char *const yadex_copyright[] =\n";
+  print "{\n";
+}
+foreach my $string (@output)
+{
+  if ($format eq 'c')
+  {
+    $string =~ s/\\/\\\\/g;		# Escape backslashes
+    $string =~ s/"/\"/g;		# Escape double quotes
+    print "  \"$string\",\n";
+  }
+  elsif ($format eq 'html')
+  {
+    $string =~ s/</\&lt;/g;		# Escape "<"
+    $string =~ s/©/\&copy;/g;		# Encode the copyright symbol
+    print "$string<br>\n";
+  }
+  elsif ($format eq 'text')
+  {
+    print "$string\n";
+  }
+  elsif ($format eq 'troff')
+  {
+    $string =~ s/\\/\\\\/g;		# Escape backslashes
+    $string =~ s/©/\\(co/g;		# Encode the copyright symbol
+    print "$string\n";
+    print ".br\n";
+  }
+  else
+  {
+    die "copyright: bad format \"$format\"\n";
+  }
+}
+if ($format eq 'c')
+{
+  print "  0\n";
+  print "};\n";
+  print "\n";
+}
+
+exit 0;
+
+
+#
+#	byname - sort() callback to sort by (lastname, firstname)
+#
+sub byname ($$)
+{
+  my ($a, $b) = @_;
+  return "$a->{name}\01$a->{firstname}" cmp "$b->{name}\01$b->{firstname}";
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/ftime.1	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,59 @@
+.TH FTIME 1
+.SH NAME
+ftime \- print access, change or modification time of files
+.SH SYNOPSIS
+\fBftime\fP [\fB-\fP{\fBa\fP|\fBc\fP|\fBm\fP}] [\fB\-f\fP \fIstring\fP] \fIfile\fP ...
+.SH DESCRIPTION
+Amazingly, there does not seem to exist any simple and portable way to
+retrieve the last modification time of a file from the shell. GNU awk, GNU
+find, perl and stat allow to do it but they're not part of the standard.
+Parsing the output of ls \-l could do, but it would be disgustingly complicated
+and the time of day is lost anyway. This program was written to plug that
+hole.
+
+If only one file is given, ftime prints just the time followed by a newline.
+If more than one file is given, ftime prints one line for each file with, on
+each line, the time and the name of the file, separated by a space.
+
+Note that if an argument is a directory, it is \fInot\fP treated specially.
+There is not sorting: files are printed in the same order in which they appear
+on the command line.
+
+.SH OPTIONS
+.SS Specifying the time to print
+.TP
+.B \-m
+Print the time of the last modification (\fBctime\fP). This is the default.
+.TP
+.B \-a
+Print the time of the last access (\fBatime\fP). By default the time printed
+is the time of the last modification (\fBmtime\fP). This option is similar to
+the \fB\-u\fP option in \fBls\fP(1).
+.TP
+.B \-c
+Print the time of the last status change (\fBctime\fP). By default the time
+printed is the time of the last modification (\fBmtime\fP). This option is
+similar to the \fB\-c\fP option in \fBls\fP(1).
+.SS Specifying the format for times
+.TP
+.BI "\-f " string
+Print the times using \fBstrftime\fP(3) and the format \fIstring\fP. By
+default, the times are printed with the format "\fB%Y\-%m\-%d %H:%M:%S\fP"
+(i.e. the ISO 8601 format \fIyyyy\fP\-\fImm\fP\-\fIdd\fP
+\fIhh\fP:\fImm\fP:\fIss\fP).
+.TP
+.B \-d
+Print the date only. This option is equivalent to "\fB\-f '%Y\-%m\-%d\fP'".
+.TP
+.B \-s
+Don't print the seconds. This option is equivalent to "\fB\-f '%Y\-%m\-%d
+%H:%M'\fP".
+.SH EXIT VALUE
+.ta 4
+\fBO\fP	OK.
+.br
+\fB1\fP	Syntax error.
+.br
+\fB2\fP	Runtime error.
+.SH SEE ALSO
+.BR strftime (3)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/ftime.c	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,172 @@
+/*
+ *	ftime.c
+ *	Print the access, change or modification time of files
+ *	AYM 1999-08-31
+ */
+
+
+/*
+ftime is Copyright © 1999 André Majorel.
+
+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 Library General Public
+License along with this library; if not, write to the Free
+Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307, USA.
+*/
+
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <time.h>
+#include <stdarg.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+
+static void err (const char *fmt, ...);
+
+
+static int verbose = 0;
+static int print_names = 1;
+static char which_time = 'm';
+static const char format_dateonly[] = "%Y-%m-%d";
+static const char format_nosecs[]   = "%Y-%m-%d %H:%M";
+static const char format_default[]  = "%Y-%m-%d %H:%M:%S";
+static const char *time_format = format_default;
+
+
+int main (int argc, char *argv[])
+{
+  int n;
+  int nfiles = 0;
+  const char **file_list = NULL;
+  time_t time = 0;
+  time_t newtime;
+  struct tm *tm;
+
+  /* Parse the command line. Put the names of the reference
+     files in <file_list>. Put the name of the output file in
+     <oname>. */
+  for (n = 1; n < argc; n++)
+  {
+    if (! strcmp (argv[n], "-a"))
+    {
+      which_time = 'a';
+    }
+    else if (! strcmp (argv[n], "-c"))
+    {
+      which_time = 'c';
+    }
+    else if (! strcmp (argv[n], "-d"))
+    {
+      time_format = format_dateonly;
+    }
+    else if (! strncmp (argv[n], "-f", 2))
+    {
+      if (argv[n][2])
+	time_format = argv[n] + 2;
+      else
+      {
+	n++;
+	if (n >= argc)
+	{
+	  err ("-f requires an argument");
+	  exit (1);
+	}
+	time_format = argv[n];
+      }
+    }
+    else if (! strcmp (argv[n], "-m"))
+    {
+      which_time = 'm';
+    }
+    else if (! strcmp (argv[n], "-s"))
+    {
+      time_format = format_nosecs;
+    }
+    else if (! strcmp (argv[n], "-v"))
+    {
+      verbose = 1;
+    }
+    else
+    {
+      file_list = realloc (file_list, (nfiles + 1) * sizeof *file_list);
+      if (file_list == NULL)
+      {
+	err ("Not enough memory");
+	exit (2);
+      }
+      file_list[nfiles] = argv[n];
+      nfiles++;
+    }
+  }
+  if (nfiles == 1)
+  {
+    print_names = 0;
+  }
+  else
+  {
+    print_names = 1;
+  }
+
+  /* Print one line for each file */
+  for (n = 0; n < nfiles; n++)
+  {
+    struct stat sbuf;
+    time_t      time;
+    char        tbuf[101];
+
+    if (stat (file_list[n], &sbuf))
+    {
+      err ("Warning: can't stat \"%s\" (%s)", file_list[n], strerror (errno));
+      continue;
+    }
+    if (which_time == 'a')
+      time = sbuf.st_atime;
+    else if (which_time == 'c')
+      time = sbuf.st_ctime;
+    else if (which_time == 'm')
+      time = sbuf.st_mtime;
+    else
+      ;  /* Ugh ? */
+
+    tm = localtime (&time);
+    strftime (tbuf, sizeof tbuf, time_format, tm);
+    fputs (tbuf, stdout);
+    if (print_names)
+    {
+      putchar (' ');
+      fputs (file_list[n], stdout);
+    }
+    putchar ('\n');
+  }
+
+  if (file_list != NULL)
+    free (file_list);
+  exit (0);
+}
+
+
+static void err (const char *fmt, ...)
+{
+  va_list list;
+  fflush (stdout);
+  fputs ("ftime: ", stderr);
+  va_start (list, fmt);
+  vfprintf (stderr, fmt, list);
+  fputc ('\n', stderr);
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/install.c	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,239 @@
+/*
+ *	install - install files
+ *	AYM 2001-04-10
+ */
+
+
+/*
+This file is Copyright © 2001 André Majorel.
+
+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 <stddef.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <utime.h>
+
+
+static void usage (void);
+static int install_file (const char ifile[], const char ofile[], mode_t omode);
+static void err (const char *fmt, ...);
+
+
+int main (int argc, char *argv[])
+{
+  int rc = 0;
+  const char *target_dir = NULL;
+  mode_t mode = 0;
+  int help = 0;
+
+  /* Parse the command line */
+  if (argc == 2 && strcmp (argv[1], "--help") == 0)
+  {
+    usage ();
+    exit (0);
+  }
+  else
+  {
+    int g;
+    while ((g = getopt (argc, argv, "d:m:")) != EOF)
+    {
+      if (g == 'd')
+	target_dir = optarg;
+      else if (g == 'm')
+	mode = (mode_t) strtol (optarg, NULL, 8);
+      else
+      {
+	err ("syntax error");
+	exit (1);
+      }
+    }
+  }
+  if (target_dir == NULL && argc - optind != 2)
+  {
+    err ("syntax error");
+    exit (1);
+  }
+
+  /* Copy all files */
+  if (target_dir == NULL)
+  {
+    if (install_file (argv[optind], argv[optind + 1], mode) != 0)
+      rc = 1;
+  }
+  else
+  {
+    int n;
+
+    for (n = optind; n < argc; n++)
+    {
+      char *ofile = NULL;
+      char *ibasename;
+
+      ibasename = strrchr (argv[n], '/');  /* FIXME unixism */
+      if (ibasename == NULL)
+	ibasename = argv[n];
+      ofile = malloc (strlen (target_dir) + strlen (ibasename) + 2);
+      if (ofile == NULL)
+      {
+	err (strerror (ENOMEM));
+	exit (1);
+      }
+      strcpy (ofile, target_dir);
+      if (strlen (ofile) > 0 && ofile[strlen (ofile) - 1] != '/')  /* FIXME */
+	strcat (ofile, "/");
+      strcat (ofile, ibasename);
+      if (install_file (argv[n], ofile, mode) != 0)
+	rc = 1;
+      free (ofile);
+    }
+  }
+
+  return rc;
+}
+
+
+static void usage (void)
+{
+  puts ("Usage:");
+  puts ("  install --help");
+  puts ("  install [-m mode] ifile ofile");
+  puts ("  install [-m mode] [-d dir] [file ...]");
+}
+
+
+static int install_file (const char ifile[], const char ofile[], mode_t omode)
+{
+  int rc       = 0;
+  FILE *ifp    = NULL;
+  FILE *ofp    = NULL;
+  char *buf    = NULL;
+  size_t bufsz = 0x4000;
+
+  ifp = fopen (ifile, "rb");
+  if (ifp == NULL)
+  {
+    err ("%s: %s", ifile, strerror (errno));
+    rc = 1;
+    goto byebye;
+  }
+  ofp = fopen (ofile, "wb");
+  if (ofp == NULL)
+  {
+    err ("%s: %s", ofile, strerror (errno));
+    rc = 1;
+    goto byebye;
+  }
+  buf = malloc (bufsz);
+  if (buf == NULL)
+  {
+    err (strerror (ENOMEM));
+    rc = 1;
+    goto byebye;
+  }
+
+  /* Copy the data */
+  {
+    size_t nbytes;
+
+    while ((nbytes = fread (buf, 1, bufsz, ifp)) != 0)
+    {
+      if (fwrite (buf, 1, nbytes, ofp) != nbytes)
+      {
+	err ("%s: write error", ofile);
+	rc = 1;
+	goto byebye;
+      }
+    }
+    if (ferror (ifp))
+    {
+      err ("%s: read error", ifile);
+      rc = 1;
+    }
+  }
+
+  /* Force the ownership to EUID:EGID. Useful if the targets
+     already exist. */
+  if (chown (ofile, geteuid (), getegid ()) != 0)
+  {
+    err ("%s: %s", ofile, strerror (errno));
+    rc = 1;
+    goto byebye;
+  }
+
+  /* Set the mode */
+  if (chmod (ofile, omode) != 0)
+  {
+    err ("%s: %s", ofile, strerror (errno));
+    rc = 1;
+    goto byebye;
+  }
+
+  /* Copy the mtime */
+  {
+    struct stat s;
+    struct utimbuf u;
+
+    if (stat (ifile, &s) != 0)
+    {
+      err ("%s: %s", ifile, strerror (errno));
+      rc = 1;
+      goto byebye;
+    }
+    u.actime  = s.st_atime;
+    u.modtime = s.st_mtime;
+    if (utime (ofile, &u) != 0)
+    {
+      err ("%s: %s", ofile, strerror (errno));
+      rc = 1;
+      goto byebye;
+    }
+  }
+
+
+byebye:
+  if (ifp != NULL)
+    fclose (ifp);
+  if (ofp != NULL)
+    if (fclose (ofp) != 0)
+    {
+      err ("%s: %s", ofile, strerror (errno));
+      rc = 1;
+    }
+  if (buf != NULL)
+    free (buf);
+  return rc;
+}
+
+
+static void err (const char *fmt, ...)
+{
+  va_list argp;
+
+  fflush (stdout);
+  fputs ("install: ", stderr);
+  va_start (argp, fmt);
+  vfprintf (stderr, fmt, argp);
+  va_end (argp);
+  fputc ('\n', stderr);
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/mkinstalldirs	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,36 @@
+#! /bin/sh
+# mkinstalldirs --- make directory hierarchy
+# Author: Noah Friedman <friedman@prep.ai.mit.edu>
+# Created: 1993-05-16
+# Last modified: 1994-03-25
+# Public domain
+
+errstatus=0
+
+for file in ${1+"$@"} ; do 
+   set fnord `echo ":$file" | sed -ne 's/^:\//#/;s/^://;s/\// /g;s/^#/\//;p'`
+   shift
+
+   pathcomp=
+   for d in ${1+"$@"} ; do
+     pathcomp="$pathcomp$d"
+     case "$pathcomp" in
+       -* ) pathcomp=./$pathcomp ;;
+     esac
+
+     if test ! -d "$pathcomp"; then
+        echo "mkdir $pathcomp" 1>&2
+        mkdir "$pathcomp" > /dev/null 2>&1 || lasterr=$?
+     fi
+
+     if test ! -d "$pathcomp"; then
+	errstatus=$lasterr
+     fi
+
+     pathcomp="$pathcomp/"
+   done
+done
+
+exit $errstatus
+
+# mkinstalldirs ends here
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/notexist.c	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,68 @@
+/*
+ *	notexist - complain if given directory entries exist
+ *	AYM 2000-09-06
+ */
+
+
+/*
+This file is Copyright © 2000 André Majorel.
+
+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 Library General Public
+License along with this library; if not, write to the Free
+Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307, USA.
+*/
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+
+int main (int argc, char *argv[])
+{
+  int n;
+
+  for (n = 1; n < argc; n++)
+  {
+    struct stat s;
+
+    if (lstat (argv[n], &s) == 0)
+    {
+      fprintf (stderr, "%s already exists. Delete it.\n", argv[n]);
+      exit (1);
+    }
+    else if (errno != ENOENT)
+    {
+      fprintf (stderr, "%s: can't lstat (%s)\n", argv[n], strerror (errno));
+      exit (1);
+    }
+    if (stat (argv[n], &s) == 0)
+    {
+      fprintf (stderr, "%s already exists. Delete it.\n", argv[n]);
+      exit (1);
+    }
+    else if (errno != ENOENT)
+    {
+      fprintf (stderr, "%s: can't stat (%s)\n", argv[n], strerror (errno));
+      exit (1);
+    }
+  }
+  exit (0);
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/process	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,42 @@
+#!/bin/sh
+#
+#	process - expand certain macro expressions in text files
+#	Usage: process <file>
+#	AYM 1999-08-13
+#
+
+# In <file>, replace occurrences of
+# - "$COPYRIGHT_MAN" by the contents of the file cache/copyright.man.
+# - "$COPYRIGHT_TXT" by the contents of the file cache/copyright.txt.
+# - "$DATE"          by the YYYY-MM-DD current time,
+# - "$FILES_ETC"     by the contents of the file obj/0/file_etc.man
+# - "$FILES_SHARE"   by the contents of the file obj/0/file_share.man
+# - "$SELF_DATE"     by the YYYY-MM-DD mtime of <file>,
+# - "$SOURCE_DATE"   by the contents of the file cache/srcdate,
+# - "$VERPREV"       by the contents of the file ./VERPREV.
+# - "$VERSION"       by the contents of the file ./VERSION.
+# Output is written on stdout.
+
+file=$1
+shift
+sed -e "/\$COPYRIGHT_MAN/ {
+	  r cache/copyright.man
+	  d
+	}
+	/\$COPYRIGHT_TXT/ {
+	  r cache/copyright.txt
+	  d
+	}
+	/\$FILES_ETC/ {
+	  r obj/0/files_etc.man
+	  d
+	}
+	/\$FILES_SHARE/ {
+	  r obj/0/files_share.man
+	  d
+	}
+	s/\$DATE/`date +%Y-%m-%d`/g
+	s/\$SELF_DATE/`obj/0/ftime -d $file`/g
+	s/\$SOURCE_DATE/`cat cache/srcdate`/g
+	s/\$VERPREV/`test -r VERPREV && cat VERPREV`/g
+	s/\$VERSION/`cat VERSION`/g" $file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/youngest	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,16 @@
+#!/usr/bin/perl
+#
+#	youngest - print the date (yyyy-mm-dd) of the last modified file
+#	Usage : youngest <file> ...
+#
+
+$mtime_max = 0;
+foreach $fic (@ARGV)
+{
+   ($dev, $ino, $mode, $nlink, $uid, $gid, $rdev, $size,
+      $atime, $mtime, $ctime, $blksize, $blocks) = stat $fic;
+   $loc_ti = localtime $mtime;
+   $mtime_max = $mtime if $mtime_max < $mtime;
+}
+($ss, $mi, $hh, $jj, $mm, $aa) = localtime $mtime_max;
+printf "%04d-%02d-%02d", $aa + 1900, $mm + 1, $jj;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/_edit.h	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,131 @@
+/*
+ *	_edit.h
+ *	AYM 1998-09-06
+ */
+
+
+/*
+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.
+*/
+
+
+#ifndef YH__EDIT	/* DO NOT INSERT ANYTHING BEFORE THIS LINE */
+#define YH__EDIT
+
+
+#include "objid.h"
+
+
+class edisplay_c;
+class Menu;
+class menubar_c;
+class modpopup_c;
+class selbox_c;
+class spot_c;
+
+
+// The numbers of the items on the menu bar
+enum
+{
+  MBI_FILE,
+  MBI_EDIT,
+  MBI_VIEW,
+  MBI_SEARCH,
+  MBI_MISC,
+  MBI_OBJECTS,
+  MBI_CHECK,
+  MBI_HELP,
+  MBI_COUNT
+};
+
+
+// The numbers of the actual menus (Menu objects)
+enum
+{
+  MBM_FILE,
+  MBM_EDIT,
+  MBM_VIEW,
+  MBM_SEARCH,
+  MBM_MISC_L,  // The "Misc. operations" menus changes with the mode
+  MBM_MISC_S,
+  MBM_MISC_T,
+  MBM_MISC_V,
+  MBM_OBJECTS,
+  MBM_CHECK,
+  MBM_HELP,
+  MBM_COUNT
+};
+
+
+typedef enum
+{
+  TOOL_NORMAL,
+  TOOL_SNAP_VERTEX
+} tool_t;
+
+
+/* This structure holds all the data necessary to an edit window. */
+// FIXME: make a class of it.
+typedef struct
+{
+  public :
+    int   mb_ino[MBI_COUNT];	// The numbers of the items on the menu bar
+    Menu *mb_menu[MBM_COUNT];	// The actual menu objects
+
+    int move_speed;		// Movement speed.
+    int extra_zoom;		// Act like the zoom was 4 times what it is
+    int obj_type;		// The mode (OBJ_LINEDEF, OBJ_SECTOR...)
+    bool global;		// Global mode (experimental)
+    tool_t tool;		// The current tool
+    int grid_step;		// The grid step
+    int grid_step_min;		// The floor of the grid step
+    int grid_step_max;		// The ceiling of the grid step
+    int grid_step_locked;	// Whether the grid step is locked
+    int grid_shown;		// Whether the grid is shown
+    int grid_snap;		// Whether objects forced to be on the grid
+    bool infobar_shown;		// Whether the info bar is shown
+    bool objinfo_shown;		// Whether the object info boxes are shown
+    bool show_object_numbers;	// Whether the object numbers are shown
+    bool show_things_squares;	// Whether the things squares are shown
+    bool show_things_sprites;	// Whether the things sprites are shown
+    int rulers_shown;		// Whether the rulers are shown (unused ?)
+    int pointer_x;		// Map coordinates of pointer
+    int pointer_y;
+    int pointer_in_window;	// If false, pointer_[xy] are not meaningful.
+    Objid clicked;		// The object that was under the pointer when
+				// when the left click occurred. If clicked on
+				// empty space, == CANVAS.
+    int click_ctrl;		// Was Ctrl pressed at the moment of the click?
+    unsigned long click_time;	// Date of last left click in ms
+    Objid highlighted;		// The highlighted object
+    SelPtr Selected;		// Linked list of selected objects (or NULL)
+
+    selbox_c   *selbox;		// The selection box
+    edisplay_c *edisplay;	// The display manager
+    menubar_c  *menubar;	// The menu bar
+    spot_c     *spot;		// The insertion spot
+
+    modpopup_c *modpopup;	// The modal popup menu (only one at a time!)
+    char modal;
+} edit_t;
+
+
+#endif  /* DO NOT ADD ANYTHING AFTER THIS LINE */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/acolours.cc	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,155 @@
+/*
+ *	acolours.cc
+ *	Allocate and free the application colours.
+ *
+ *	By "application colours", I mean the colours used to draw
+ *	the windows, the menus and the map, as opposed to the
+ *	"game colours" which depend on the game (they're in the
+ *	PLAYPAL lump) and are used to draw the game graphics
+ *	(flats, textures, sprites...).
+ *
+ *	The game colours are handled in gcolour1.cc and gcolour2.cc.
+ *
+ *	AYM 1998-11-29
+ */
+
+
+/*
+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 "acolours.h"
+#include "gfx.h"
+#include "rgb.h"
+
+
+typedef struct
+{
+  rgb_c rgb;
+  char deleted;
+} ac_table_entry_t;
+
+static ac_table_entry_t *table     = 0;  // The list
+static acolour_t        table_size = 0;  // The size of the list
+static acolour_t        ac_count   = 0;  // The number of entries really used
+
+
+/*
+ *	add_app_colour
+ *	Add colour <rgb> to the list of application colours
+ *	and return a brand new application colour# for it.
+ */
+pcolour_t add_app_colour (rgb_c rgb)
+{
+  size_t i;
+
+  for (i = 0; i < table_size; i++)
+    if (table[i].deleted)
+      break;
+
+  if (i == table_size)
+  {
+    table_size++;
+    table = (ac_table_entry_t *) realloc (table, table_size * sizeof *table);
+    if (table == NULL)
+      fatal_error (msg_nomem);
+  }
+  ac_count++;
+  table[i].rgb     = rgb;
+  table[i].deleted = 0;
+  return i;
+}
+
+
+/*
+ *	delete_app_colour
+ *	Remove colour# <acn> from the list of application colours.
+ */
+void delete_app_colour (acolour_t acn)
+{
+  if (acn >= table_size)
+    fatal_error ("delete_app_colour called with non-existent colour %d", acn);
+  if (table[acn].deleted)
+    fatal_error ("colour %d deleted twice", acn);
+  ac_count--;
+  table[acn].deleted = 1;
+}
+
+
+/* FIXME a very quick-and-dirty way of preventing
+   changes to the list done between commit_() and
+   uncommit_() to corrupt things. */
+static size_t committed_colours = 0;
+
+
+/*
+ *	commit_app_colours
+ *	Return an array containing the physical colour numbers
+ *	for the application colours in the list.
+ */
+pcolour_t *commit_app_colours ()
+{
+  verbmsg ("colours: committing %d colours\n", ac_count);
+
+  /* First create an array of RGB values
+     for all the colours in the list. */
+  verbmsg ("colours: rgb_values %p\n");
+  rgb_c *rgb_values = new rgb_c[ac_count];
+  rgb_c *rgb = rgb_values;
+  int items_on_line = 0;
+  for (size_t n = 0; n < table_size; n++)
+    if (! table[n].deleted)
+    {
+      if (items_on_line == 0)
+	verbmsg ("colours: committing: ");
+      verbmsg ("%d ", int (rgb - rgb_values));
+      *rgb++ = table[n].rgb;
+      if (++items_on_line == 16)
+      {
+	verbmsg ("\n");
+	items_on_line = 0;
+      }
+    }
+  if (items_on_line != 0)
+    verbmsg ("\n");
+
+  // Then do the actual allocation.
+  committed_colours = ac_count;
+  pcolour_t *app_colours = alloc_colours (rgb_values, committed_colours);
+  delete[] rgb_values;
+  return app_colours;
+}
+
+
+/*
+ *	uncommit_app_colours
+ *	Free all the colours that were allocated by alloc_app_colours().
+ *	They are _not_ removed from the list !
+ */
+void uncommit_app_colours (pcolour_t *app_colours)
+{
+  free_colours (app_colours, committed_colours);
+  committed_colours = 0;
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/acolours.h	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,24 @@
+/*
+ *	acolours.h
+ *	Allocate and free the application colours.
+ *
+ *	By "application colours", I mean the colours used to draw
+ *	the windows, the menus and the map, as opposed to the
+ *	"game colours" which depend on the game (they're in the
+ *	PLAYPAL lump) and are used to draw the game graphics
+ *	(flats, textures, sprites...).
+ *
+ *	The game colours are handled in gcolour1.cc and gcolour2.cc.
+ *
+ *	AYM 1998-11-29
+ */
+
+
+#include "colour.h"
+
+
+pcolour_t add_app_colour (rgb_c rgb);
+void delete_app_colour (acolour_t acn);
+pcolour_t *commit_app_colours ();
+void uncommit_app_colours (pcolour_t *app_colours);
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/aym.cc	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,378 @@
+/*
+ *	aym.cc
+ *	Misc. functions
+ *	AYM 1997-??-??
+ */
+
+
+/*
+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 "game.h"
+
+
+/*
+ *	levelname2levelno
+ *	Used to know if directory entry is ExMy or MAPxy
+ *	For "ExMy" (case-insensitive),  returns 10x + y
+ *	For "ExMyz" (case-insensitive), returns 100*x + 10y + z
+ *	For "MAPxy" (case-insensitive), returns 1000 + 10x + y
+ *	E0My, ExM0, E0Myz, ExM0z are not considered valid names.
+ *	MAP00 is considered a valid name.
+ *	For other names, returns 0.
+ */
+int levelname2levelno (const char *name)
+{
+  const unsigned char *s = (const unsigned char *) name;
+  if (toupper (s[0]) == 'E'
+   && isdigit (s[1])
+   && s[1] != '0'
+   && toupper (s[2]) == 'M'
+   && isdigit (s[3])
+   && s[3] != '0'
+   && s[4] == '\0')
+    return 10 * dectoi (s[1]) + dectoi (s[3]);
+  if (yg_level_name == YGLN_E1M10
+   && toupper (s[0]) == 'E'
+   && isdigit (s[1])
+   && s[1] != '0'
+   && toupper (s[2]) == 'M'
+   && isdigit (s[3])
+   && s[3] != '0'
+   && isdigit (s[4])
+   && s[5] == '\0')
+    return 100 * dectoi (s[1]) + 10 * dectoi (s[3]) + dectoi (s[4]);
+  if (toupper (s[0]) == 'M'
+   && toupper (s[1]) == 'A'
+   && toupper (s[2]) == 'P'
+   && isdigit (s[3])
+   && isdigit (s[4])
+   && s[5] == '\0')
+    return 1000 + 10 * dectoi (s[3]) + dectoi (s[4]);
+  return 0;
+}
+
+
+/*
+ *	levelname2rank
+ *	Used to sort level names.
+ *	Identical to levelname2levelno except that, for "ExMy",
+ *	it returns 100x + y, so that
+ *	- f("E1M10") = f("E1M9") + 1
+ *	- f("E2M1")  > f("E1M99")
+ *	- f("E2M1")  > f("E1M99") + 1
+ *	- f("MAPxy") > f("ExMy")
+ *	- f("MAPxy") > f("ExMyz")
+ */
+int levelname2rank (const char *name)
+{
+  const unsigned char *s = (const unsigned char *) name;
+  if (toupper (s[0]) == 'E'
+   && isdigit (s[1])
+   && s[1] != '0'
+   && toupper (s[2]) == 'M'
+   && isdigit (s[3])
+   && s[3] != '0'
+   && s[4] == '\0')
+    return 100 * dectoi (s[1]) + dectoi (s[3]);
+  if (yg_level_name == YGLN_E1M10
+   && toupper (s[0]) == 'E'
+   && isdigit (s[1])
+   && s[1] != '0'
+   && toupper (s[2]) == 'M'
+   && isdigit (s[3])
+   && s[3] != '0'
+   && isdigit (s[4])
+   && s[5] == '\0')
+    return 100 * dectoi (s[1]) + 10 * dectoi (s[3]) + dectoi (s[4]);
+  if (toupper (s[0]) == 'M'
+   && toupper (s[1]) == 'A'
+   && toupper (s[2]) == 'P'
+   && isdigit (s[3])
+   && isdigit (s[4])
+   && s[5] == '\0')
+    return 1000 + 10 * dectoi (s[3]) + dectoi (s[4]);
+  return 0;
+}
+
+
+/*
+ *	spec_path
+ *	Extract the path of a spec
+ */
+const char *spec_path (const char *spec)
+{
+  static char path[Y_PATH + 1];
+  size_t n;
+
+  *path = '\0';
+  strncat (path, spec, sizeof path - 1);
+  for (n = strlen (path); n > 0 && ! al_fisps (path[n-1]); n--)
+    ;
+  path[n] = '\0';
+  return path;
+}
+
+
+/*
+ *	fncmp
+ *	Compare two filenames
+ *	For Unix, it's a simple strcmp.
+ *	For DOS, it's case insensitive and "/" and "\" are equivalent.
+ *	FIXME: should canonicalize both names and compare that.
+ */
+int fncmp (const char *name1, const char *name2)
+{
+#if defined Y_DOS
+  char c1, c2;
+  for (;;)
+  {
+    c1 = tolower ((unsigned char) *name1++);
+    c2 = tolower ((unsigned char) *name2++);
+    if (c1=='\\')
+      c1 = '/';
+    if (c2=='\\')
+      c2 = '/';
+    if (c1 != c2)
+      return c1-c2;
+    if (!c1)
+      return 0;
+  }
+#elif defined Y_UNIX
+  return strcmp (name1, name2);
+#endif
+}
+
+
+/*
+ *	is_absolute
+ *	Tell whether a file name is absolute or relative.
+ *
+ *	Note: for DOS, a filename of the form "d:foo" is
+ *	considered absolute, even though it's technically
+ *	relative to the	current working directory of "d:".
+ *	My reasoning is that someone who wants to specify a
+ *	name that's relative to one of the standard
+ *	directories is not going to put a "d:" in front of it.
+ */
+int is_absolute (const char *filename)
+{
+#if defined Y_UNIX
+return *filename == '/';
+#elif defined Y_DOS
+return *filename == '/'
+   || *filename == '\\'
+   || isalpha (*filename) && filename[1] == ':';
+#endif
+}
+
+
+/*
+ *	y_stricmp
+ *	A case-insensitive strcmp()
+ *	(same thing as DOS stricmp() or GNU strcasecmp())
+ */
+int y_stricmp (const char *s1, const char *s2)
+{
+for (;;)
+   {
+   if (tolower (*s1) != tolower (*s2))
+      return (unsigned char) *s1 - (unsigned char) *s2;
+   if (! *s1)
+      if (! *s2)
+         return 0;
+      else
+	 return -1;
+   if (! *s2)
+      return 1;
+   s1++;
+   s2++;
+   }
+}
+
+
+/*
+ *	y_strnicmp
+ *	A case-insensitive strncmp()
+ *	(same thing as DOS strnicmp() or GNU strncasecmp())
+ */
+int y_strnicmp (const char *s1, const char *s2, size_t len)
+{
+while (len-- > 0)
+   {
+   if (tolower (*s1) != tolower (*s2))
+      return (unsigned char) *s1 - (unsigned char) *s2;
+   if (! *s1)
+      if (! *s2)
+         return 0;
+      else
+	 return -1;
+   if (! *s2)
+      return 1;
+   s1++;
+   s2++;
+   }
+return 0;
+}
+
+
+/*
+ *	y_snprintf
+ *	If available, snprintf(). Else sprintf().
+ */
+int y_snprintf (char *buf, size_t size, const char *fmt, ...)
+{
+va_list args;
+va_start (args, fmt);
+#ifdef Y_SNPRINTF
+return vsnprintf (buf, size, fmt, args);
+#else
+return vsprintf (buf, fmt, args);
+#endif
+}
+
+
+/*
+ *	y_vsnprintf
+ *	If available, vsnprintf(). Else vsprintf().
+ */
+int y_vsnprintf (char *buf, size_t size, const char *fmt, va_list args)
+{
+#ifdef Y_SNPRINTF
+return vsnprintf (buf, size, fmt, args);
+#else
+return vsprintf (buf, fmt, args);
+#endif
+}
+
+
+/*
+ *	y_strupr
+ *	Upper-case a string
+ */
+void y_strupr (char *string)
+{
+  while (*string)
+  {
+    *string = toupper (*string);
+    string++;
+  }
+}
+
+/*
+ *	is_one_of
+ *	Return non-zero if <s> is equal (in the strcmp() sense)
+ *	to one of the other strings (retrieved from the argument
+ *	list as const char *). The last string must be followed
+ *	by (const char *) 0.
+ */
+int is_one_of (const char *needle, ...)
+{
+  va_list args;
+  va_start (args, needle);
+  for (;;)
+  {
+    const char *haystack = va_arg (args, const char *);
+    if (haystack == Y_NULL)
+      break;
+    if (! strcmp (needle, haystack))
+      return 1;
+  }
+  return 0;
+}
+
+
+
+/*
+ *	file_exists
+ *	Check whether a file exists and is readable.
+ *	Returns true if it is, false if it isn't.
+ */
+bool file_exists (const char *filename)
+{
+  FILE *test;
+
+  if ((test = fopen (filename, "rb")) == NULL)
+    return 0;
+  fclose (test);
+  return 1;
+}
+
+
+/*
+ *	y_filename
+ *	Copies into <buf> a string that is a close as possible
+ *	to <filename> but is guaranteed to be no longer than
+ *	<size> - 1 and contain only printable characters. Non
+ *	printable characters are replaced by question marks.
+ *	Excess characters are replaced by an ellipsis.
+ */
+void y_filename (char *buf, size_t size, const char *filename)
+{
+  if (size == 0)
+    return;
+  if (size == 1)
+  {
+    *buf = '\0';
+    return;
+  }
+  size_t len    = strlen (filename);
+  size_t maxlen = size - 1;
+
+  if (len > 3 && maxlen <= 3)  // Pathological case, fill with dots
+  {
+    memset (buf, '.', maxlen);
+    buf[maxlen] = '\0';
+    return;
+  }
+
+  size_t len1 = len;
+  size_t len2 = 0;
+  if (len > maxlen)
+  {
+    len1 = (maxlen - 3) / 2;
+    len2 = maxlen - 3 - len1;
+  }
+  char *p = buf;
+  for (size_t n = 0; n < len1; n++)
+  {
+    *p++ = y_isprint (*filename) ? *filename : '?';
+    filename++;
+  }
+  if (len2 > 0)
+  {
+    *p++ = '.';
+    *p++ = '.';
+    *p++ = '.';
+    filename += len - len1 - len2;
+    for (size_t n = 0; n < len2; n++)
+    {
+      *p++ = y_isprint (*filename) ? *filename : '?';
+      filename++;
+    }
+  }
+  *p++ = '\0';
+}
+ 
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/aym.h	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,194 @@
+/*
+ *	aym.h
+ *	Misc. functions
+ *	AYM 1999-03-15
+ */
+
+
+/*
+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.
+*/
+
+
+#ifndef YH_AYM  /* DO NOT INSERT ANYTHING BEFORE THIS LINE */
+#define YH_AYM
+
+
+int levelname2levelno (const char *name);
+int levelname2rank (const char *name);
+const char *spec_path (const char *spec);
+int fncmp (const char *name1, const char *name2);
+int is_absolute (const char *filename);
+int y_stricmp (const char *s1, const char *s2);
+int y_strnicmp (const char *s1, const char *s2, size_t len);
+int y_snprintf (char *buf, size_t size, const char *fmt, ...);
+int y_vsnprintf (char *buf, size_t size, const char *fmt, va_list args);
+void y_strupr (char *string);
+int is_one_of (const char *needle, ...);
+bool file_exists (const char *);
+void y_filename (char *buf, size_t size, const char *path);
+
+
+/*
+ *	within
+ *	Is <value> >= <lower_bound> and <= <upper_bound> ?
+ */
+inline int within (int value, int lower_bound, int upper_bound)
+{
+  return value >= lower_bound && value <= upper_bound;
+}
+
+
+/*
+ *	outside
+ *	Is <value> < <lower_bound> or > <upper_bound> ?
+ */
+inline int outside (int value, int lower_bound, int upper_bound)
+{
+  return value < lower_bound || value > upper_bound;
+}
+
+
+/*
+ *	dectoi
+ *	If <c> is a decimal digit ("[0-9]"), return its value.
+ *	Else, return a negative number.
+ */
+inline int dectoi (char c)
+{
+  if (isdigit ((unsigned char) c))
+    return c - '0';
+  else
+    return -1;
+}
+
+
+/*
+ *	hextoi
+ *	If <c> is a hexadecimal digit ("[0-9A-Fa-f]"), return its value.
+ *	Else, return a negative number.
+ */
+inline int hextoi (char c)
+{
+  if (isdigit ((unsigned char) c))
+    return c - '0';
+  else if (c >= 'a' && c <= 'f')
+    return c - 'a' + 10;
+  else if (c >= 'A' && c <= 'F')
+    return c - 'A' + 10;
+  else
+    return -1;
+}
+
+
+/*
+ *	b36toi
+ *	If <c> is a base 36 digit ("[0-9A-Za-z]"), return its value.
+ *	Else, return a negative number.
+ */
+inline int b36toi (char c)
+{
+  if (isdigit ((unsigned char) c))
+    return c - '0';
+  else if (islower (c))
+    return c - 'a' + 10;
+  else if (isupper (c))
+    return c - 'A' + 10;
+  else
+    return -1;
+}
+
+
+/*
+ *	y_isident - return true iff <c> is one of a-z, A-Z, 0-9 or "_".
+ *
+ *	Intentionally not using isalpha() and co. because I
+ *	don't want the results to depend on the locale.
+ */
+inline bool y_isident (char c)
+{
+  switch (c)
+  {
+    case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
+    case 'g': case 'h': case 'i': case 'j': case 'k': case 'l':
+    case 'm': case 'n': case 'o': case 'p': case 'q': case 'r':
+    case 's': case 't': case 'u': case 'v': case 'w': case 'x':
+    case 'y': case 'z':
+
+    case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
+    case 'G': case 'H': case 'I': case 'J': case 'K': case 'L':
+    case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R':
+    case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
+    case 'Y': case 'Z':
+
+    case '0': case '1': case '2': case '3': case '4': case '5':
+    case '6': case '7': case '8': case '9':
+
+    case '_':
+
+      return true;
+
+    default:
+
+      return false;
+  }
+}
+
+
+/*
+ *	fnewline
+ *	Write a newline to a binary file. For Unix, LF. For
+ *	other platforms, CR LF.
+ *	Return EOF on failure.
+ */
+inline int fnewline (FILE *fd)
+{
+#ifdef Y_UNIX
+  return putc ('\n', fd);
+#else
+  return putc ('\r', fd), putc ('\n', fd);
+#endif
+}
+
+
+/*
+ *	round_up
+ *	Round a value up to the next multiple of quantum.
+ *
+ *	Both the value and the quantum are supposed to be positive.
+ */
+inline void round_up (int& value, int quantum)
+{
+  value = ((value + quantum - 1) / quantum) * quantum;
+}
+
+
+/*
+ *	y_isprint
+ *	Is <c> a printable character in ISO-8859-1 ?
+ */
+inline bool y_isprint (char c)
+{
+  return (c & 0x60) && (c != 0x7f);
+}
+
+
+#endif  /* DO NOT ADD ANYTHING AFTER THIS LINE */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/bench.cc	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,99 @@
+/*
+ *	bench.cc
+ *	Benchmark functions.
+ *	AYM 2000-04-13
+ */
+
+
+/*
+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 <time.h>
+#include <sys/times.h>
+
+#include "gfx.h"
+#include "img.h"
+#include "pic2img.h"
+#include "wadres.h"
+
+
+
+static void bench_LoadPicture ();
+
+
+/*
+ *	benchmark - run the benchmarks specified by <what>.
+ */
+void benchmark (const char *what)
+{
+  // Insert parsing of <what> here
+  if (! strcmp (what, "loadpic"))
+    bench_LoadPicture ();
+}
+
+
+/*
+ *	bench_LoadPicture - run a benchmark of LoadPicture()
+ */
+static void bench_LoadPicture ()
+{
+  const char *sprite_name = "TROOA1";
+  unsigned long iterations = 100000;
+  const int width = 100;
+  const int height = 100;
+  Lump_loc sprite_loc;
+  
+  wad_res.sprites.loc_by_name (sprite_name, sprite_loc);
+  if (sprite_loc.wad == 0)
+    fprintf (stderr, "Could not locate sprite %s\n", sprite_name);
+
+  Img img (width, height, false);
+  struct tms t0;
+  times (&t0);
+  for (unsigned long n = 0; n < iterations; n++)
+    LoadPicture (img, sprite_name, sprite_loc, 0, 0, 0, 0);
+  struct tms t1;
+  times (&t1);
+
+// Glibc 2.1 (?) has a broken CLOCKS_PER_SEC.
+#ifndef CLOCKS_PER_SEC
+#define CLOCKS_PER_SEC CLK_TCK
+#endif
+  const char *unit  = "s";
+  double value = (double) (t1.tms_utime - t0.tms_utime)
+		 / CLOCKS_PER_SEC / iterations;
+  if (value < 1E-3)
+  {
+    unit = "µs";
+    value *= 1000000;
+  }
+  else if (value < 1.0)
+  {
+    unit = "ms";
+    value *= 1000;
+  }
+  printf ("LoadPicture: %f %s per call\n", value, unit);
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/bench.h	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,15 @@
+/*
+ *	bench.h
+ *	Benchmark functions.
+ *	AYM 2000-04-13
+ */
+
+
+#ifndef YH_BENCH  /* DO NOT INSERT ANYTHING BEFORE THIS LINE */
+#define YH_BENCH
+
+
+void benchmark (const char *what);
+
+
+#endif  /* DO NOT ADD ANYTHING AFTER THIS LINE */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/bitvec.cc	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,13 @@
+/*
+ *	bitvec.cc
+ *	AYM 1999-08-15
+ */
+
+
+#include "yadex.h"
+#include "bitvec.h"
+
+
+const char _bitvec_msg1[] = "bitvec::frob: invalid op = %d";
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/bitvec.h	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,110 @@
+/*
+ *	bitvec.h
+ *	A rudimentary bit vector class.
+ *	AYM 1998-11-22
+ */
+
+
+/*
+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.
+*/
+
+
+#ifndef YH_BITVEC  /* DO NOT INSERT ANYTHING BEFORE THIS LINE */
+#define YH_BITVEC
+
+
+#include <limits.h>
+
+#include "yerror.h"
+#include "ymemory.h"
+
+
+typedef enum
+   {
+   BV_SET    = 's',
+   BV_CLEAR  = 'c',
+   BV_TOGGLE = 't'
+   } bitvec_op_t;
+
+
+extern const char _bitvec_msg1[];
+
+
+class bitvec_c
+   {
+   public :
+      bitvec_c (size_t n_elements)
+         { 
+	 a = (char *) GetMemory (n_elements / CHAR_BIT + 1);
+ 	 memset (a, 0, n_elements / CHAR_BIT + 1);
+         _n_elements = n_elements;
+         }
+
+      ~bitvec_c ()
+         {
+         FreeMemory (a);
+         }
+
+      size_t nelements () const  // Return the number of elements
+         {
+         return _n_elements;
+         }
+
+      int get (size_t n) const  // Get bit <n>
+         {
+         return a[n/CHAR_BIT] & (1 << (n % CHAR_BIT));
+         }
+
+      void set (size_t n)  // Set bit <n> to 1
+         {
+         a[n/CHAR_BIT] |= 1 << (n % CHAR_BIT);
+         }
+
+      void unset (size_t n)  // Set bit <n> to 0
+         {
+         a[n/CHAR_BIT] &= ~(1 << (n % CHAR_BIT));
+         }
+
+      void toggle (size_t n)  // Toggle bit <n>
+ 	 {
+	 a[n/CHAR_BIT] ^= (1 << (n % CHAR_BIT));
+	 }
+
+      void frob (size_t n, bitvec_op_t op)  // Set, unset or toggle bit <n>
+         {
+	 if (op == BV_SET)
+	    set (n);
+	 else if (op == BV_CLEAR)
+	    unset (n);
+	 else if (op == BV_TOGGLE)
+	    toggle (n);
+	 else
+	    nf_bug (_bitvec_msg1, (int) op);
+         }
+
+   private :
+      size_t _n_elements;
+      char *a;
+   };
+
+
+#endif  /* DO NOT ADD ANYTHING AFTER THIS LINE */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/cfgfile.cc	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,1450 @@
+/*
+ *	cfgfile.cc
+ *	AYM 1998-09-30
+ */
+
+/*
+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.
+
+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 <sys/types.h>
+#include <sys/stat.h>
+
+#include "cfgfile.h"
+#include "gfx.h"
+#include "help1.h"
+#include "levels.h"
+#include "locate.h"
+#include "trace.h"
+#include "windim.h"
+
+
+const char config_file_magic[] = "# Yadex configuration file version 4";
+
+
+/*
+ *	Description of the command line arguments and config file keywords
+ */
+typedef enum
+{
+  // Boolean (toggle)
+  // Receptacle is of type bool
+  // data_ptr is of type (bool *)
+  OPT_BOOLEAN,
+
+  // "yes", "no", "ask"
+  // Receptacle is of type confirm_t
+  // data_ptr is of type confirm_t
+  OPT_CONFIRM,
+
+  // Integer number,
+  // Receptacle is of type int
+  // data_ptr is of type (int *)
+  OPT_INTEGER,
+
+  // Unsigned long integer
+  // Receptacle is of type unsigned
+  // data_ptr is of type (unsigned long *)
+  OPT_UNSIGNED,
+
+  // Window dimension, either integer (pixels) or integer%
+  // (percentage of total display dimension)
+  // Receptacle is of type ...
+  // data_ptr is of type ...
+  OPT_WINDIM,
+
+  // String
+  // Receptacle is of type (char[9])
+  // data_ptr is of type (char *)
+  OPT_STRINGBUF8,
+
+  // String
+  // Receptacle is of type (const char *)
+  // data_ptr is of type (const char **)
+  OPT_STRINGPTR,
+
+  // String, but store in a list
+  // Receptacle is of type ??
+  // data_ptr is of type ??
+  OPT_STRINGPTRACC,
+
+  // List of strings
+  // Receptacle is of type (const char *[])
+  // data_ptr is of type (const char ***)
+  OPT_STRINGPTRLIST,
+
+  // End of the options description
+  OPT_END
+} opt_type_t;
+
+typedef struct
+{
+  const char *long_name;	// Command line arg. or keyword
+  const char *short_name;	// Abbreviated command line argument
+  opt_type_t opt_type;		// Type of this option
+  const char *flags;		// Flags for this option :
+				// "1" = process only on pass 1 of
+				//       parse_command_line_options()
+				// "b" = BGI only (ignored ifndef Y_BGI)
+				// "x" = X only (ignored ifndef Y_X11)
+  const char *desc;		// Description of the option
+  void *data_ptr;		// Pointer to the data
+} opt_desc_t;
+
+/* The first option has neither long name nor short name.
+   It is used for "lonely" arguments (i.e. file names). */
+opt_desc_t options[] =		// Description of the command line options
+{
+  { 0,
+    0,
+    OPT_STRINGPTRACC,
+    0,
+    "Patch wad file",
+    &PatchWads },
+
+  { "autoscroll",
+    0,
+    OPT_BOOLEAN,
+    0,
+    "Enable autoscrolling",
+    &autoscroll },
+
+  { "autoscroll_amp",
+    0,
+    OPT_UNSIGNED,
+    0,
+    "Amp. of scrolling (% of screen size)",
+    &autoscroll_amp },
+
+  { "autoscroll_edge",
+    0,
+    OPT_UNSIGNED,
+    0,
+    "Max. dist. to edge (pixels)",
+    &autoscroll_edge },
+
+  { 0,
+    "b",
+    OPT_STRINGPTR,
+    0,
+    "Run benchmark and exit successfully",
+    &bench },
+
+  { "bgi",
+    0,
+    OPT_STRINGPTR,
+    "b",
+    "(BGI only) BGI video driver",
+    &BGIDriver },
+
+  { "blindly_swap_sidedefs",
+    0,
+    OPT_BOOLEAN,
+    0,
+    "Blindly swap sidedefs on a linedef",
+    &blindly_swap_sidedefs },
+
+  { "cirrus_cursor",
+    "cc",
+    OPT_BOOLEAN,
+    "b",
+    "(BGI only) Cirrus hardware cursor",
+    &CirrusCursor },
+
+  { "config_file",
+    "f",
+    OPT_STRINGPTR,
+    "1",
+    "Config file",
+    &config_file },
+
+  { "copy_linedef_reuse_sidedefs",
+    0,
+    OPT_BOOLEAN,
+    0,
+    "Use same sidedefs as original linedef",
+    &copy_linedef_reuse_sidedefs },
+
+  { "debug",
+    "d",
+    OPT_BOOLEAN,
+    0,
+    "Debug mode",
+    &Debug },
+
+  { "default_ceiling_height",
+    0,
+    OPT_INTEGER,
+    0,
+    "Default ceiling height",
+    &default_ceiling_height },
+
+  { "default_ceiling_texture",
+    0,
+    OPT_STRINGBUF8,
+    0,
+    "Default ceiling texture",
+    default_ceiling_texture },
+
+  { "default_floor_height",
+    0,
+    OPT_INTEGER,
+    0,
+    "Default floor height",
+    &default_floor_height },
+
+  { "default_floor_texture",
+    0,
+    OPT_STRINGBUF8,
+    0,
+    "Default floor texture",
+    default_floor_texture },
+
+  { "default_light_level",
+    0,
+    OPT_INTEGER,
+    0,
+    "Default light level",
+    &default_light_level },
+
+  { "default_lower_texture",
+    0,
+    OPT_STRINGBUF8,
+    0,
+    "Default lower texture",
+    default_lower_texture },
+
+  { "default_middle_texture",
+    0,
+    OPT_STRINGBUF8,
+    0,
+    "Default middle texture",
+    default_middle_texture },
+
+  { "default_thing",
+    0,
+    OPT_INTEGER,
+    0,
+    "Default thing number",
+    &default_thing },
+
+  { "default_upper_texture",
+    0,
+    OPT_STRINGBUF8,
+    0,
+    "Default upper texture",
+    default_upper_texture },
+
+  { "digit_zoom_base",
+    0,
+    OPT_INTEGER,
+    0,
+    "[0]-[9]: base zoom factor (in %)",
+    &digit_zoom_base },
+
+  { "digit_zoom_step",
+    0,
+    OPT_INTEGER,
+    0,
+    "[0]-[9]: step between factors (in %)",
+    &digit_zoom_step },
+
+  { "double_click_timeout",
+    0,
+    OPT_INTEGER,
+    0,
+    "Max delay in ms between clicks",
+    &double_click_timeout },
+
+  { "expert",
+    0,
+    OPT_BOOLEAN,
+    0,
+    "Expert mode",
+    &Expert },
+
+  { "fake_cursor",
+    "fc",
+    OPT_BOOLEAN,
+    0,
+    "(X11 only) Fake cursor",
+    &FakeCursor },
+
+  { "file",
+    0,
+    OPT_STRINGPTRLIST,
+    0,
+    "Patch wad file",
+    &PatchWads },
+
+  { "font",
+    "fn",
+    OPT_STRINGPTR,
+    0,
+    "(X11 only) Font name",
+    &font_name },
+
+  { "game",
+    "g",
+    OPT_STRINGPTR,
+    0,
+    "Game",
+    &Game },
+
+  { "grid_max",
+    0,
+    OPT_INTEGER,
+    0,
+    "Max grid step (map units)",
+    &GridMax },
+
+  { "grid_min",
+    0,
+    OPT_INTEGER,
+    0,
+    "Min grid step (map units)",
+    &GridMin },
+
+  { "grid_pixels_min",
+    0,
+    OPT_INTEGER,
+    0,
+    "Min grid step (pixels)",
+    &grid_pixels_min },
+
+  { "height",
+    "h",
+    OPT_WINDIM,
+    "x",
+    "(X11 only) Initial window height",
+    &initial_window_height },
+
+  { "help",
+    "?",
+    OPT_BOOLEAN,
+    "1",
+    "Show usage summary",
+    &show_help },
+
+  { "idle_sleep_ms",
+    0,
+    OPT_INTEGER,
+    0,
+    "ms to sleep before XPending()",
+    &idle_sleep_ms },
+
+  { "info_bar",
+    0,
+    OPT_BOOLEAN,
+    0,
+    "Show the info bar",
+    &InfoShown },
+
+  { "insert_vertex_split_linedef",
+    0,
+    OPT_CONFIRM,
+    0,
+    "Split ld after ins. vertex",
+    &insert_vertex_split_linedef },
+
+  { "insert_vertex_merge_vertices",
+    0,
+    OPT_CONFIRM,
+    0,
+    "Merge vertices after ins. vertex",
+    &insert_vertex_merge_vertices },
+
+  { "iwad1",
+    "i1",
+    OPT_STRINGPTR,
+    0,
+    "The name of the Doom/Ultimate D. iwad",
+    &Iwad1 },
+
+  { "iwad2",
+    "i2",
+    OPT_STRINGPTR,
+    0,
+    "The name of the Doom II/Final D. iwad",
+    &Iwad2 },
+
+  { "iwad3",
+    "i3",
+    OPT_STRINGPTR,
+    0,
+    "The name of the Heretic iwad",
+    &Iwad3 },
+
+  { "iwad4",
+    "i4",
+    OPT_STRINGPTR,
+    0,
+    "The name of the Hexen iwad",
+    &Iwad4 },
+
+  { "iwad5",
+    "i5",
+    OPT_STRINGPTR,
+    0,
+    "The name of the Strife iwad",
+    &Iwad5 },
+
+  { "iwad6",
+    "i6",
+    OPT_STRINGPTR,
+    0,
+    "The name of the Doom alpha 0.2 iwad",
+    &Iwad6 },
+
+  { "iwad7",
+    "i7",
+    OPT_STRINGPTR,
+    0,
+    "The name of the Doom alpha 0.4 iwad",
+    &Iwad7 },
+
+  { "iwad8",
+    "i8",
+    OPT_STRINGPTR,
+    0,
+    "The name of the Doom alpha 0.5 iwad",
+    &Iwad8 },
+
+  { "iwad9",
+    "i9",
+    OPT_STRINGPTR,
+    0,
+    "The name of the Doom press rel. iwad",
+    &Iwad9 },
+
+  { "iwad10",
+    "i10",
+    OPT_STRINGPTR,
+    0,
+    "The name of the Strife 1.0 iwad",
+    &Iwad10 },
+
+#ifdef AYM_MOUSE_HACKS
+  { "mouse_horizontal_sens",
+    "mh",
+    OPT_INTEGER,
+    "b",
+    "(BGI only) Mouse horizontal sensitivity",
+    &MouseMickeysH },
+
+  { "mouse_vertical_sens",
+    "mv",
+    OPT_INTEGER,
+    "b",
+    "(BGI only) Mouse vertical sensitivity",
+    &MouseMickeysV },
+#endif
+
+  { "no_pixmap",
+    "P",
+    OPT_BOOLEAN,
+    0,
+    "(X11 only) Use no pixmap",
+    &no_pixmap },
+
+  { "pwad",
+    "pw",
+    OPT_STRINGPTRACC,
+    0,
+    "Pwad file to load",
+    &PatchWads },
+
+  { "quiet",
+    "q",
+    OPT_BOOLEAN,
+    0,
+    "Quiet mode",
+    &Quiet },
+
+  { "quieter",
+    "qq",
+    OPT_BOOLEAN,
+    0,
+    "Quieter mode",
+    &Quieter },
+
+  { "scroll_less",
+    0,
+    OPT_UNSIGNED,
+    0,
+    "Amp. of scrolling (% of screen size)",
+    &scroll_less },
+
+  { "scroll_more",
+    0,
+    OPT_UNSIGNED,
+    0,
+    "Amp. of scrolling (% of screen size)",
+    &scroll_more },
+
+  { "select0",
+    "s0",
+    OPT_BOOLEAN,
+    0,
+    "Automatic selection of 0th object",
+    &Select0 },
+
+  { "sprite_scale",
+    0,
+    OPT_INTEGER,
+    0,
+    "Relative scale of sprites",
+    &sprite_scale },
+
+  { "swap_buttons",
+    "sb",
+    OPT_BOOLEAN,
+    0,
+    "Swap mouse buttons",
+    &SwapButtons },
+
+  { "text_dot",
+    "td",
+    OPT_BOOLEAN,
+    0,
+    "DrawScreenText debug flag",
+    &text_dot },
+
+  { "verbose",
+    "v",
+    OPT_BOOLEAN,
+    "1",
+    "Verbose mode",
+    &verbose },
+
+  { "video",
+    "V",
+    OPT_INTEGER,
+    "b",
+    "(BGI only) Video mode",
+    &VideoMode },
+
+  { "welcome_message",
+    0, 
+    OPT_BOOLEAN,
+    0,
+    "Print welcome message",
+    &welcome_message },
+
+  { "width",
+    "w",
+    OPT_WINDIM,
+    "x",
+    "(X11 only) Initial window width",
+    &initial_window_width },
+
+  { "zoom_default",
+    "z",
+    OPT_INTEGER,
+    0,
+    "Initial zoom factor",
+    &zoom_default },
+
+  { "zoom_step",
+    0,
+    OPT_INTEGER,
+    0,
+    "Step between zoom factors (in %)",
+    &zoom_step },
+
+  { 0,
+    0,
+    OPT_END,
+    0,
+    0,
+    0 }
+};
+
+
+typedef enum
+{
+  CFG_PARSE_            = 0x00,
+  CFG_PARSE_MAGIC_ERROR = 0x01,
+  CFG_PARSE_MAGIC_WARN  = 0x02,
+  CFG_PARSE_ANAL_NAME   = 0x04,
+  CFG_PARSE_ANAL_SYNTAX = 0x08
+} cfg_parse_flags_t;
+
+
+static void append_item_to_list (const char ***list, const char *item);
+static int parse_config_file (const char *filename,
+  cfg_parse_flags_t flags = CFG_PARSE_);
+static confirm_t confirm_e2i (const char *external);
+static const char *confirm_i2e (confirm_t internal);
+
+
+/*
+ *	parse_config_file_default - parse the default config file(s)
+ *
+ *	Return non-zero if parse error occurred (i.e. at least
+ *	one call to parse_config_file() returned non-zero), zero
+ *	otherwise.
+ */
+int parse_config_file_default ()
+{
+  int rc = 0;
+  int matches;
+  const char *pathname;
+  const char *name = "yadex.cfg";
+  Locate locate (yadex_etc_path, name, true);
+
+  for (matches = 0; (pathname = locate.get_next ()) != NULL; matches++)
+  {
+    printf ("Reading config file \"%s\".\n", pathname);
+    int r = parse_config_file (pathname);
+    if (r != 0)
+      rc = 1;
+  }
+  if (matches == 0)
+    warn ("%s: not found\n", name);
+  return rc;
+}
+
+
+/*
+ *	parse_config_file_user - parse a user-specified config file
+ *
+ *	Return non-zero if the file couldn't be found or if
+ *	parse error occurred (i.e. parse_config_file() returned
+ *	non-zero), zero otherwise.
+ */
+int parse_config_file_user (const char *name)
+{
+  const char *pathname;
+  Locate locate (yadex_etc_path, name, false);
+  
+  pathname = locate.get_next ();
+  if (pathname == NULL)
+  {
+    err ("%s: not found", name);
+    return 1;
+  }
+  printf ("Reading config file \"%s\".\n", pathname);
+  return parse_config_file (pathname);
+}
+
+
+/*
+ *	parse_config_file - try to parse a config file by pathname.
+ *
+ *	If (flags & CFG_PARSE_MAGIC_ERROR) is true, the file must
+ *	begin with config_file_magic on a line by itself or the
+ *	function will exit immediately with a non-zero value.
+ *
+ *	If (flags & CFG_PARSE_MAGIC_WARN) is true, the file must
+ *	begin with config_file_magic on a line by itself or the
+ *	function will print a warning.
+ *
+ *	If (flags & CFG_PARSE_ANAL_NAME) is true, unknown
+ *	variables name cause the function to return immediately
+ *	with a non-zero value. Otherwise, unknown variables
+ *	cause the line to be skipped with a warning and do not
+ *	cause the return value to be non-zero.
+ *
+ *	If (flags & CFG_PARSE_ANAL_SYNTAX) is true, lines that
+ *	do not follow the <name> = <value> syntax cause the
+ *	function to emit an error message and return immediately
+ *	with a non-zero value. Otherwise, such lines are simply
+ *	ignored with a warning message and do not cause the
+ *	return value to be non-zero.
+ *
+ *	Return 0 on success, <>0 on failure.
+ */
+#define RETURN_FAILURE do { rc = 1; goto byebye; } while (0)
+static int parse_config_file (const char *filename, cfg_parse_flags_t flags)
+{
+  int   rc = 0;
+  FILE *cfgfile;
+  char  line[1024];
+
+  cfgfile = fopen (filename, "r");
+  if (cfgfile == NULL)
+  {
+    err ("Can't open config file \"%s\" (%s)", filename, strerror (errno));
+    RETURN_FAILURE;
+  }
+
+  /* The first line of the configuration file must
+     contain exactly config_file_magic. */
+  if (fgets (line, sizeof line, cfgfile) == NULL
+     || memcmp (line, config_file_magic, sizeof config_file_magic - 1)
+     || line[sizeof config_file_magic - 1] != '\n'
+     || line[sizeof config_file_magic] != '\0')
+  {
+    if (flags & CFG_PARSE_MAGIC_ERROR)
+    {
+      err ("%s(1): bad magic, not a valid Yadex configuration file", filename);
+      err ("Perhaps a leftover from a previous version of Yadex ?");
+      RETURN_FAILURE;
+    }
+    if (flags & CFG_PARSE_MAGIC_WARN)
+      warn ("%s(1): bad magic, perhaps from a different version of Yadex\n",
+	  filename);
+    rewind (cfgfile);
+  }
+
+  // Execute one line on each iteration
+  for (unsigned lnum = 1; fgets (line, sizeof line, cfgfile) != NULL; lnum++)
+  {
+    char *name  = 0;
+    char *value = 0;
+    char *p     = line;
+
+    // Skip leading whitespace
+    while (isspace (*p))
+      p++;
+
+    // Skip comments
+    if (*p == '#')
+      continue;
+
+    // Remove trailing newline
+    {
+      size_t len = strlen (p);
+      if (len >= 1 && p[len - 1] == '\n')
+	p[len - 1] = '\0';
+    }
+
+    // Skip empty lines
+    if (*p == '\0')
+       continue;
+
+    // Make <name> point on the <name> field
+    name = p;
+    while (y_isident (*p))
+      p++;
+    if (*p == '\0')
+    {
+      if (flags & CFG_PARSE_ANAL_SYNTAX)
+      {
+	err ("%s(%u): expected an \"=\"", filename, lnum);
+	RETURN_FAILURE;
+      }
+      else
+      {
+	warn ("%s(%u): expected an \"=\", skipping\n", filename, lnum);
+	goto next_line;
+      }
+    }
+    if (*p == '=')
+    {
+      // Mark the end of the option name
+      *p = '\0';
+    }
+    else
+    {
+      // Mark the end of the option name
+      *p = '\0';
+      p++;
+      // Skip blanks after the option name
+      while (isspace ((unsigned char) *p))
+	p++;
+      if (*p != '=')
+      {
+	if (flags & CFG_PARSE_ANAL_SYNTAX)
+	{
+	  err ("%s(%u,%d): expected an \"=\"",
+	    filename, lnum, 1 + (int) (p - line));
+	  RETURN_FAILURE;
+	}
+	else
+	{
+	  warn ("%s(%u,%d): expected an \"=\", skipping\n",
+	    filename, lnum, 1 + (int) (p - line));
+	  goto next_line;
+	}
+      }
+    }
+    p++;
+
+    /* First parameter : <value> points on the first character.
+       Put a NUL at the end. If there is a second parameter,
+       holler. */
+    while (isspace ((unsigned char) *p))
+      p++;
+    value = p;
+    {
+      unsigned char *p2 = (unsigned char *) value;
+      while (*p2 != '\0' && ! isspace (*p2))
+	p2++;
+      if (*p2 != '\0')  // There's trailing whitespace after 1st parameter
+      {
+	for (unsigned char *p3 = p2; *p3 != '\0'; p3++)
+	  if (! isspace (*p3))
+	  {
+	    err ("%s(%u,%d): extraneous argument",
+	      filename, lnum, 1 + (int) ((char *) p3 - line));
+	    RETURN_FAILURE;
+	  }
+      }
+      *p2 = '\0';
+    }
+
+    for (const opt_desc_t *o = options + 1; ; o++)
+    {
+      if (o->opt_type == OPT_END)
+      {
+	if (flags & CFG_PARSE_ANAL_NAME)
+	{
+	  err ("%s(%u): invalid variable \"%s\"", filename, lnum, name);
+	  RETURN_FAILURE;
+	}
+	else
+	{
+	  warn ("%s(%u): invalid variable \"%s\", skipping\n",
+	    filename, lnum, name);
+	  goto next_line;
+	}
+      }
+      if (! o->long_name || strcmp (name, o->long_name) != 0)
+        continue;
+
+      if (o->flags != NULL && strchr (o->flags, '1'))
+	 break;
+#if ! defined Y_BGI
+      if (o->flags != NULL && strchr (o->flags, 'b'))
+	 break;
+#endif
+#if ! defined Y_X11
+      if (o->flags != NULL && strchr (o->flags, 'x'))
+	 break;
+#endif
+      switch (o->opt_type)
+      {
+	case OPT_BOOLEAN:
+	  if (! strcmp (value, "yes") || ! strcmp (value, "true")
+	   || ! strcmp (value, "on") || ! strcmp (value, "1"))
+	  {
+	    if (o->data_ptr)
+	      *((bool *) (o->data_ptr)) = true;
+	  }
+	  else if (! strcmp (value, "no") || ! strcmp (value, "false")
+		|| ! strcmp (value, "off") || ! strcmp (value, "0"))
+	  {
+	    if (o->data_ptr)
+	      *((bool *) (o->data_ptr)) = false;
+	  }
+	  else
+	  {
+	    err ("%s(%u): invalid value for option %s: \"%s\"",
+	      filename, lnum, name, value);
+	    RETURN_FAILURE;
+	  }
+	  break;
+
+	case OPT_CONFIRM:
+	  if (o->data_ptr)
+	    *((confirm_t *) o->data_ptr) = confirm_e2i (value);
+	  break;
+
+	case OPT_INTEGER:
+	  if (o->data_ptr)
+	    *((int *) (o->data_ptr)) = atoi (value);
+	  break;
+
+	case OPT_UNSIGNED:
+	  if (o->data_ptr)
+	  {
+	    if (*value == '\0')
+	    {
+	      err ("%s(%u,%d): missing argument",
+	        filename, lnum, 1 + (int) (value - line));
+	      RETURN_FAILURE;
+	    }
+	    bool neg = false;
+	    if (value[0] == '-')
+	      neg = true;
+	    char *endptr;
+	    errno = 0;
+	    *((unsigned long *) (o->data_ptr)) = strtoul (value, &endptr, 0);
+	    if (*endptr != '\0' && ! isspace (*endptr))
+	    {
+	      err ("%s(%u,%d): illegal character in unsigned integer",
+		filename, lnum, 1 + (int) (endptr - line));
+	      RETURN_FAILURE;
+	    }
+	    /* strtoul() sets errno to ERANGE if overflow. In
+	       addition, we don't want any non-zero negative
+	       numbers. In terms of regexp, /^(0x)?0*$/i. */
+	    if
+	    (
+	      errno != 0
+	      || neg
+	        && !
+		(
+		  strspn (value + 1, "0") == strlen (value + 1)
+		  || value[1] == '0'
+		    && tolower (value[2]) == 'x'
+		    && strspn (value + 3, "0") == strlen (value + 3)
+		)
+	    )
+	    {
+	      err ("%s(%u,%d): unsigned integer out of range",
+		filename, lnum, 1 + (int) (value - line));
+	      RETURN_FAILURE;
+	    }
+	  }
+	  break;
+
+	case OPT_WINDIM:
+	  if (o->data_ptr)
+	    if (((Win_dim *) (o->data_ptr))->set (value))
+	    {
+	      err ("%s(%u): bad dimension spec \"%s\"", filename, lnum, value);
+	      RETURN_FAILURE;
+	    }
+	  break;
+
+	case OPT_STRINGBUF8:
+	  if (o->data_ptr)
+	    al_scps ((char *) o->data_ptr, value, 8);
+	  break;
+
+	case OPT_STRINGPTR:
+	  {
+	    char *dup = (char *) GetMemory (strlen (value) + 1);
+	    strcpy (dup, value);
+	    if (o->data_ptr)
+	      *((char **) (o->data_ptr)) = dup;
+	    break;
+	  }
+
+	case OPT_STRINGPTRACC:
+	  {
+	    char *dup = (char *) GetMemory (strlen (value) + 1);
+	    strcpy (dup, value);
+	    if (o->data_ptr)
+	      append_item_to_list ((const char ***) o->data_ptr, dup);
+	    break;
+	  }
+
+	case OPT_STRINGPTRLIST:
+	  while (*value != '\0')
+	  {
+	    char *v = value;
+	    while (*v != '\0' && ! isspace ((unsigned char) *v))
+	      v++;
+	    char *dup = (char *) GetMemory (v - value + 1);
+	    memcpy (dup, value, v - value);
+	    dup[v - value] = '\0';
+	    if (o->data_ptr)
+	      append_item_to_list ((const char ***) o->data_ptr, dup);
+	    while (isspace (*v))
+	      v++;
+	    value = v;
+	  }
+	  break;
+
+	default:
+	  {
+	    nf_bug ("%s(%u): unknown option type %d",
+	      filename, lnum, (int) o->opt_type);
+	    RETURN_FAILURE;
+	  }
+      }
+      break;
+    }
+    next_line:;
+  }
+
+  byebye:
+  if (cfgfile != 0)
+    fclose (cfgfile);
+  return rc;
+}
+
+
+/*
+ *	parse_command_line_options
+ *	If <pass> is set to 1, ignores all options except those
+ *	that have the "1" flag.
+ *	Else, ignores all options that have the "1" flag.
+ *	If an error occurs, report it with err()
+ *	and returns non-zero. Else, returns 0.
+ */
+int parse_command_line_options (int argc, const char *const *argv, int pass)
+{
+  const opt_desc_t *o;
+
+  while (argc > 0)
+  {
+    int ignore;
+
+    // Which option is this ?
+    if (**argv != '-' && **argv != '+')
+    {
+      o = options;
+      argc++;
+      argv--;
+    }
+    else
+      for (o = options + 1; ; o++)
+      {
+	if (o->opt_type == OPT_END)
+	{
+	  err ("invalid option: \"%s\"", argv[0]);
+	  return 1;
+	}
+	if (o->short_name && ! strcmp (argv[0]+1, o->short_name)
+	 || o->long_name  && ! strcmp (argv[0]+1, o->long_name))
+	  break;
+      }
+
+    // If this option has the "1" flag but pass is not 1
+    // or it doesn't but pass is 1, ignore it.
+    ignore = (o->flags != NULL && strchr (o->flags, '1')) != (pass == 1);
+
+    switch (o->opt_type)
+    {
+      case OPT_BOOLEAN:
+	if (argv[0][0] == '-')
+	{
+	  if (o->data_ptr && ! ignore)
+	     *((bool *) (o->data_ptr)) = true;
+	}
+	else
+	{
+	  if (o->data_ptr && ! ignore)
+	     *((bool *) (o->data_ptr)) = false;
+	}
+	break;
+
+      case OPT_CONFIRM:
+	if (argc <= 1)
+	{
+	  err ("missing argument after \"%s\"", argv[0]);
+	  return 1;
+	}
+	argv++;
+	argc--;
+	if (o->data_ptr && ! ignore)
+	   *((confirm_t *) o->data_ptr) = confirm_e2i (argv[0]);
+	break;
+
+      case OPT_INTEGER:
+	if (argc <= 1)
+	{
+	  err ("missing argument after \"%s\"", argv[0]);
+	  return 1;
+	}
+	argv++;
+	argc--;
+	if (o->data_ptr && ! ignore)
+	  *((int *) (o->data_ptr)) = atoi (argv[0]);
+	break;
+
+      case OPT_UNSIGNED:
+        if (argc <= 1)
+	{
+	  err ("missing argument after \"%s\"", argv[0]);
+	  return 1;
+	}
+	argv++;
+	argc--;
+	if (o->data_ptr && ! ignore)
+	{
+	  const char *value = argv[0];
+	  if (*value == '\0')
+	  {
+	    err ("not an unsigned integer \"%s\"", value);
+	    return 1;
+	  }
+	  bool neg = false;
+	  if (*value == '-')
+	    neg = true;
+	  char *endptr;
+	  errno = 0;
+	  *((unsigned long *) (o->data_ptr)) = strtoul (value, &endptr, 0);
+	  while (*endptr != '\0' && isspace (*endptr))
+	    endptr++;
+	  if (*endptr != '\0')
+	  {
+	    err ("illegal characters in unsigned int \"%s\"", endptr);
+	    return 1;
+	  }
+	  /* strtoul() sets errno to ERANGE if overflow. In
+	     addition, we don't want any non-zero negative
+	     numbers. In terms of regexp, /^(0x)?0*$/i. */
+	  if
+	  (
+	    errno != 0
+	    || neg
+	      && !
+	      (
+		strspn (value + 1, "0") == strlen (value + 1)
+		|| value[1] == '0'
+		  && tolower (value[2]) == 'x'
+		  && strspn (value + 3, "0") == strlen (value + 3)
+	      )
+	  )
+	  {
+	    err ("unsigned integer out of range \"%s\"", value);
+	    return 1;
+	  }
+	}
+	break;
+
+      case OPT_WINDIM:
+	if (argc <= 1)
+	{
+	  err ("missing argument after \"%s\"", argv[0]);
+	  return 1;
+	}
+	argv++;
+	argc--;
+	if (o->data_ptr && ! ignore)
+	  if (((Win_dim *) (o->data_ptr))->set (argv[0]))
+	  {
+	    err ("bad dimension spec \"%s\"", argv[0]);
+	    return 1;
+	  }
+	break;
+
+      case OPT_STRINGBUF8:
+	if (argc <= 1)
+	{
+	  err ("missing argument after \"%s\"", argv[0]);
+	  return 1;
+	}
+	argv++;
+	argc--;
+	if (o->data_ptr && ! ignore)
+	  al_scps ((char *) o->data_ptr, argv[0], 8);
+	break;
+
+      case OPT_STRINGPTR:
+	if (argc <= 1)
+	{
+	  err ("missing argument after \"%s\"", argv[0]);
+	  return 1;
+	}
+	argv++;
+	argc--;
+	if (o->data_ptr && ! ignore)
+	  *((const char **) (o->data_ptr)) = argv[0];
+	break;
+
+      case OPT_STRINGPTRACC:
+	if (argc <= 1)
+	{
+	  err ("missing argument after \"%s\"", argv[0]);
+	  return 1;
+	}
+	argv++;
+	argc--;
+	if (o->data_ptr && ! ignore)
+	  append_item_to_list ((const char ***) o->data_ptr, argv[0]);
+	break;
+
+      case OPT_STRINGPTRLIST:
+	if (argc <= 1)
+	{
+	  err ("missing argument after \"%s\"", argv[0]);
+	  return 1;
+	}
+	while (argc > 1 && argv[1][0] != '-' && argv[1][0] != '+')
+	{
+	  argv++;
+	  argc--;
+	  if (o->data_ptr && ! ignore)
+	    append_item_to_list ((const char ***) o->data_ptr, argv[0]);
+	}
+	break;
+
+      default:
+	{
+	  nf_bug ("unknown option type (%d)", (int) o->opt_type);
+	  return 1;
+	}
+    }
+    argv++;
+    argc--;
+  }
+  return 0;
+}
+
+
+/*
+ *	dump_parameters
+ *	Print a list of the parameters with their current value.
+ */
+void dump_parameters (FILE *fp)
+{
+  const opt_desc_t *o;
+  int desc_maxlen = 0;
+  int name_maxlen = 0;
+
+  for (o = options + 1; o->opt_type != OPT_END; o++)
+  {
+    int len = strlen (o->desc);
+    desc_maxlen = al_amax (desc_maxlen, len);
+    if (o->long_name)
+    {
+      len = strlen (o->long_name);
+      name_maxlen = al_amax (name_maxlen, len);
+    }
+  }
+
+  for (o = options + 1; o->opt_type != OPT_END; o++)
+  {
+    if (! o->long_name)
+      continue;
+    fprintf (fp, "%-*s  %-*s  ",name_maxlen, o->long_name, desc_maxlen, o->desc);
+    if (o->opt_type == OPT_BOOLEAN)
+      fprintf (fp, "%s", *((bool *) o->data_ptr) ? "enabled" : "disabled");
+    else if (o->opt_type == OPT_CONFIRM)
+      fputs (confirm_i2e (*((confirm_t *) o->data_ptr)), fp);
+    else if (o->opt_type == OPT_STRINGBUF8)
+      fprintf (fp, "\"%s\"", (char *) o->data_ptr);
+    else if (o->opt_type == OPT_STRINGPTR)
+    {
+      if (o->data_ptr)
+	fprintf (fp, "\"%s\"", *((char **) o->data_ptr));
+      else
+	fprintf (fp, "--none--");
+    }
+    else if (o->opt_type == OPT_INTEGER)
+      fprintf (fp, "%d", *((int *) o->data_ptr));
+    else if (o->opt_type == OPT_UNSIGNED)
+      fprintf (fp, "%lu", *((unsigned long *) o->data_ptr));
+    else if (o->opt_type == OPT_WINDIM)
+    {
+      char buf[50];  // Much slack
+      ((Win_dim *) (o->data_ptr))->string (buf, sizeof buf);
+      fputs (buf, fp);
+    }
+    else if (o->opt_type == OPT_STRINGPTRACC
+	  || o->opt_type == OPT_STRINGPTRLIST)
+    {
+      if (o->data_ptr)
+      {
+	char **list;
+	for (list = *((char ***) o->data_ptr); list && *list; list++)
+	  fprintf (fp, "\"%s\" ", *list);
+	if (list == *((char ***) o->data_ptr))
+	  fprintf (fp, "--none--");
+      }
+      else
+	fprintf (fp, "--none--");
+    }
+    fputc ('\n', fp);
+  }
+}
+
+
+/*
+ *	dump_command_line_options
+ *	Print a list of all command line options (usage message).
+ */
+void dump_command_line_options (FILE *fd)
+{
+  const opt_desc_t *o;
+  int desc_maxlen = 0;
+  int name_maxlen = 0;
+
+  for (o = options + 1; o->opt_type != OPT_END; o++)
+  {
+    int len;
+    if (! o->short_name)
+      continue;
+    len = strlen (o->desc);
+    desc_maxlen = al_amax (desc_maxlen, len);
+    if (o->long_name)
+    {
+      len = strlen (o->long_name);
+      name_maxlen = al_amax (name_maxlen, len);
+    }
+  }
+
+  for (o = options; o->opt_type != OPT_END; o++)
+  {
+    if (! o->short_name)
+      continue;
+#if ! defined Y_BGI
+    if (o->flags && strchr (o->flags, 'b'))
+      continue;
+#endif
+#if ! defined Y_X11
+    if (o->flags && strchr (o->flags, 'x'))
+      continue;
+#endif
+    if (o->short_name)
+      fprintf (fd, " -%-3s ", o->short_name);
+    else
+      fprintf (fd, "      ");
+    if (o->long_name)
+      fprintf (fd, "-%-*s ", name_maxlen, o->long_name);
+    else
+      fprintf (fd, "%*s", name_maxlen + 2, "");
+    switch (o->opt_type)
+    {
+      case OPT_BOOLEAN:       fprintf (fd, "            "); break;
+      case OPT_CONFIRM:       fprintf (fd, "yes|no|ask  "); break;
+      case OPT_STRINGBUF8:
+      case OPT_STRINGPTR:
+      case OPT_STRINGPTRACC:  fprintf (fd, "<string>    "); break;
+      case OPT_INTEGER:       fprintf (fd, "<integer>   "); break;
+      case OPT_UNSIGNED:      fprintf (fd, "<unsigned>  "); break;
+      case OPT_WINDIM:        fprintf (fd, "<integer>[%%]"); break;
+      case OPT_STRINGPTRLIST: fprintf (fd, "<string> ..."); break;
+      case OPT_END: ;  // This line is here only to silence a GCC warning.
+    }
+    fprintf (fd, " %s\n", o->desc);
+  }
+}
+
+
+/*
+ *	confirm_e2i
+ *	Convert the external representation of a confirmation
+ *	flag ("yes", "no", "ask", "ask_once") to the internal
+ *	representation (YC_YES, YC_NO, YC_ASK, YC_ASK_ONCE or
+ *	'\0' if none).
+ */
+static confirm_t confirm_e2i (const char *external)
+{
+  if (external != NULL)
+  {
+    if (! strcmp (external, "yes"))
+      return YC_YES;
+    if (! strcmp (external, "no"))
+      return YC_NO;
+    if (! strcmp (external, "ask"))
+      return YC_ASK;
+    if (! strcmp (external, "ask_once"))
+      return YC_ASK_ONCE;
+  }
+  return YC_ASK;
+}
+
+
+/*
+ *	confirm_i2e
+ *	Convert the internal representation of a confirmation
+ *	flag (YC_YES, YC_NO, YC_ASK, YC_ASK_ONCE) to the external
+ *	representation ("yes", "no", "ask", "ask_once" or "?").
+ */
+static const char *confirm_i2e (confirm_t internal)
+{
+  if (internal == YC_YES)
+    return "yes";
+  if (internal == YC_NO)
+    return "no";
+  if (internal == YC_ASK)
+    return "ask";
+  if (internal == YC_ASK_ONCE)
+    return "ask_once";
+  return "?";
+}
+
+
+/*
+ *	append_item_to_list
+ *	Append a string to a null-terminated string list
+ */
+static void append_item_to_list (const char ***list, const char *item)
+{
+  int i;
+
+  i = 0;
+  if (*list != 0)
+  {
+    // Count the number of elements in the list (last = null)
+    while ((*list)[i] != 0)
+      i++;
+    // Expand the list
+    *list = (const char **) ResizeMemory (*list, (i + 2) * sizeof **list);
+  }
+  else
+  {
+    // Create a new list
+    *list = (const char **) GetMemory (2 * sizeof **list);
+  }
+  // Append the new element
+  (*list)[i] = item;
+  (*list)[i + 1] = 0;
+}
+
+
+#include <string>
+#include <vector>
+
+const size_t MAX_TOKENS = 10;
+
+/*
+ *	word_splitting - perform word splitting on a string
+ */
+int word_splitting (std::vector<std::string>& tokens, const char *string)
+{
+  size_t      ntokens     = 0;
+  const char *iptr        = string;
+  const char *token_start = 0;
+  bool        in_token    = false;
+  bool        quoted      = false;
+
+  /* break the line into whitespace-separated tokens.
+     whitespace can be enclosed in double quotes. */
+  for (; ; iptr++)
+  {
+    if (*iptr == '\n' || *iptr == '\0')
+      break;
+
+    else if (*iptr == '"')
+      quoted = ! quoted;
+
+    // "#" at the beginning of a token
+    else if (! in_token && ! quoted && *iptr == '#')
+      break;
+
+    // First character of token
+    else if (! in_token && (quoted || ! isspace (*iptr)))
+    {
+      ntokens++;
+      if (ntokens > MAX_TOKENS)
+	return 2;  // Too many tokens
+      in_token = true;
+    }
+
+    // First space between two tokens
+    else if (in_token && ! quoted && isspace (*iptr))
+    {
+      tokens.push_back (std::string (token_start, iptr - token_start));
+      in_token = false;
+    }
+  }
+  
+  if (in_token)
+    tokens.push_back (std::string (token_start, iptr - token_start));
+
+  if (quoted)
+    return 1;  // Unmatched double quote
+  return 0;
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/cfgfile.h	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,14 @@
+/*
+ *	cfgfile.h
+ *	AYM 1998-09-30
+ */
+
+
+int parse_config_file_default ();
+int parse_config_file_user (const char *name);
+int  parse_command_line_options (int argc, const char *const *argv, int pass);
+void dump_parameters (FILE *fd);
+void dump_command_line_options (FILE *fd);
+extern const char config_file_magic[];
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/checks.cc	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,939 @@
+/*
+ *	checks.cc
+ *	Level integrity checking
+ *	AYM 1998-01-29
+ */
+
+
+/*
+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 "checks.h"
+#include "dialog.h"
+#include "gamesky.h"
+#include "gfx.h"
+#include "gotoobj.h"
+#include "levels.h"
+#include "objects.h"
+#include "objid.h"
+#include "oldmenus.h"
+#include "selectn.h"
+
+
+static void CheckingObjects ();
+
+
+/*
+ *	CheckLevel
+ *	check the level consistency
+ *	FIXME should be integrated into editloop.cc
+ */
+void CheckLevel (int x0, int y0) /* SWAP! */
+{
+const char *line5 = 0;
+
+if (Registered)
+   {
+   /* Commented out AYM 19971130 - wouldn't work with Doom 2
+   if (! FindMasterDir (MasterDir, "TEXTURE2"))
+      NumVertexes--;
+   else
+   */
+      line5 = "Check texture names";
+   }
+switch (vDisplayMenu (x0, y0, "Check level consistency",
+                     "Number of objects",		YK_, 0,
+                     "Check if all Sectors are closed",	YK_, 0,
+                     "Check all cross-references",	YK_, 0,
+                     "Check for missing textures",	YK_, 0,
+                     line5,				YK_, 0,
+                     NULL))
+   {
+   case 1:
+      Statistics ();
+      break;
+   case 2:
+      CheckSectors ();
+      break;
+   case 3:
+      CheckCrossReferences ();
+      break;
+   case 4:
+      CheckTextures ();
+      break;
+   case 5:
+      CheckTextureNames ();
+      break;
+   }
+}
+
+
+/*
+   display number of objects, etc.
+*/
+
+void Statistics ()
+{
+int height;
+int width;
+int out_x0;
+int out_y0;
+int text_x0;
+int text_y0;
+
+width  = 2 * BOX_BORDER + 2 * WIDE_HSPACING + 33 * FONTW;
+height = 2 * BOX_BORDER + 2 * WIDE_VSPACING + 9 * FONTH;
+out_x0 = (ScrMaxX + 1 - width) / 2;
+out_y0 = (ScrMaxY + 1 - height) / 2;
+text_x0 = out_x0 + BOX_BORDER + WIDE_HSPACING;
+text_y0 = out_y0 + BOX_BORDER + WIDE_VSPACING;
+HideMousePointer ();
+DrawScreenBox3D (out_x0, out_y0, out_x0 + width - 1, out_y0 + height - 1);
+set_colour (WHITE);
+DrawScreenText (text_x0, text_y0, "Statistics");
+DrawScreenText (-1, -1, "");
+
+if (! Things)
+   set_colour (WINFG_DIM);
+else
+   set_colour (WINFG);
+DrawScreenText (-1, -1, "Number of things:   %4d (%lu K)", NumThings,
+ ((unsigned long) NumThings * sizeof (struct Thing) + 512L) / 1024L);
+
+if (! Vertices)
+   set_colour (WINFG_DIM);
+else
+   set_colour (WINFG);
+DrawScreenText (-1, -1, "Number of vertices: %4d (%lu K)", NumVertices,
+ ((unsigned long) NumVertices * sizeof (struct Vertex) + 512L) / 1024L);
+
+if (! LineDefs)
+   set_colour (WINFG_DIM);
+else
+   set_colour (WINFG);
+DrawScreenText (-1, -1, "Number of linedefs: %4d (%lu K)", NumLineDefs,
+ ((unsigned long) NumLineDefs * sizeof (struct LineDef) + 512L) / 1024L);
+
+if (! SideDefs)
+   set_colour (WINFG_DIM);
+else
+   set_colour (WINFG);
+DrawScreenText (-1, -1, "Number of sidedefs: %4d (%lu K)", NumSideDefs,
+ ((unsigned long) NumSideDefs * sizeof (struct SideDef) + 512L) / 1024L);
+
+if (! Sectors)
+   set_colour (WINFG_DIM);
+else
+   set_colour (WINFG);
+DrawScreenText (-1, -1, "Number of sectors:  %4d (%lu K)", NumSectors,
+ ((unsigned long) NumSectors * sizeof (struct Sector) + 512L) / 1024L);
+
+DrawScreenText (-1, -1, "");
+set_colour (WINTITLE);
+DrawScreenText (-1, -1, "Press any key to continue...");
+get_key_or_click ();
+ShowMousePointer ();
+}
+
+
+/*
+   display a message while the user is waiting...
+*/
+
+static void CheckingObjects ()
+{
+DisplayMessage (-1, -1, "Grinding...");
+}
+
+
+/*
+   display a message, then ask if the check should continue (prompt2 may be NULL)
+*/
+
+bool CheckFailed (int x0, int y0, char *prompt1, char *prompt2, bool fatal,
+    bool &first_time)
+{
+int key;
+size_t maxlen;
+
+if (fatal)
+   maxlen = 44;
+else
+   maxlen = 27;
+if (strlen (prompt1) > maxlen)
+   maxlen = strlen (prompt1);
+if (prompt2 && strlen (prompt2) > maxlen)
+   maxlen = strlen (prompt2);
+int width = 2 * BOX_BORDER + 2 * WIDE_HSPACING + FONTW * maxlen;
+int height = 2 * BOX_BORDER + 2 * WIDE_VSPACING + FONTH * (prompt2 ? 6 : 5);
+if (x0 < 0)
+   x0 = (ScrMaxX - width) / 2;
+if (y0 < 0)
+   y0 = (ScrMaxY - height) / 2;
+int text_x0 = x0 + BOX_BORDER + WIDE_HSPACING;
+int text_y0 = y0 + BOX_BORDER + WIDE_VSPACING;
+int cur_y = text_y0;
+HideMousePointer ();
+DrawScreenBox3D (x0, y0, x0 + width - 1, y0 + height - 1);
+set_colour (LIGHTRED);
+DrawScreenText (text_x0, cur_y, "Verification failed:");
+if (first_time)
+   Beep ();
+set_colour (WHITE);
+DrawScreenText (text_x0, cur_y += FONTH, prompt1);
+LogMessage ("\t%s\n", prompt1);
+if (prompt2)
+   {
+   DrawScreenText (text_x0, cur_y += FONTH, prompt2);
+   LogMessage ("\t%s\n", prompt2);
+   }
+if (fatal)
+   {
+   DrawScreenText (text_x0, cur_y += 2 * FONTH,
+     "The game will crash if you play with this level.");
+   set_colour (WINTITLE);
+   DrawScreenText (text_x0, cur_y += FONTH,
+     "Press any key to see the object");
+   LogMessage ("\n");
+   }
+else
+   {
+   set_colour (WINTITLE);
+   DrawScreenText (text_x0, cur_y += 2 * FONTH,
+     "Press Esc to see the object,");
+   DrawScreenText (text_x0, cur_y += FONTH,
+     "or any other key to continue");
+   }
+key = get_key ();
+if (key != YK_ESC)
+   {
+   DrawScreenBox3D (x0, y0, x0 + width - 1, y0 + height - 1);
+//   DrawScreenText (x0 + 10 + 4 * (maxlen - 26), y0 + 28,
+//      "Verifying other objects...");
+   }
+ShowMousePointer ();
+first_time = false;
+return (key == YK_ESC);
+}
+
+
+/*
+   check if all sectors are closed
+*/
+
+void CheckSectors () /* SWAP! */
+{
+int        s, n, sd;
+char huge *ends;
+char       msg1[80], msg2[80];
+bool       first_time = true;
+
+CheckingObjects ();
+LogMessage ("\nVerifying Sectors...\n");
+ObjectsNeeded (OBJ_LINEDEFS, OBJ_SIDEDEFS, 0);
+ends = (char huge *) GetFarMemory (NumVertices);
+for (s = 0; s < NumSectors; s++)
+   {
+   /* clear the "ends" array */
+   for (n = 0; n < NumVertices; n++)
+      ends[n] = 0;
+   /* for each sidedef bound to the Sector, store a "1" in the "ends" */
+   /* array for its starting Vertex, and a "2" for its ending Vertex  */
+   for (n = 0; n < NumLineDefs; n++)
+      {
+      sd = LineDefs[n].sidedef1;
+      if (sd >= 0 && SideDefs[sd].sector == s)
+	 {
+	 ends[LineDefs[n].start] |= 1;
+	 ends[LineDefs[n].end] |= 2;
+	 }
+      sd = LineDefs[n].sidedef2;
+      if (sd >= 0 && SideDefs[sd].sector == s)
+	 {
+	 ends[LineDefs[n].end] |= 1;
+	 ends[LineDefs[n].start] |= 2;
+	 }
+      }
+   /* every entry in the "ends" array should be "0" or "3" */
+   for (n = 0; n < NumVertices; n++)
+      {
+      if (ends[n] == 1)
+	 {
+	 sprintf (msg1, "Sector #%d is not closed!", s);
+	 sprintf (msg2, "There is no sidedef ending at Vertex #%d", n);
+	 if (CheckFailed (-1, -1, msg1, msg2, 0, first_time))
+	    {
+	    GoToObject (Objid (OBJ_VERTICES, n));
+	    return;
+	    }
+	 }
+      if (ends[n] == 2)
+	 {
+	 sprintf (msg1, "Sector #%d is not closed!", s);
+	 sprintf (msg2, "There is no sidedef starting at Vertex #%d", n);
+	 if (CheckFailed (-1, -1, msg1, msg2, 0, first_time))
+	    {
+	    GoToObject (Objid (OBJ_VERTICES, n));
+	    return;
+	    }
+	 }
+      }
+   }
+FreeFarMemory (ends);
+
+/*
+   Note from RQ:
+      This is a very simple idea, but it works!  The first test (above)
+      checks that all Sectors are closed.  But if a closed set of LineDefs
+      is moved out of a Sector and has all its "external" SideDefs pointing
+      to that Sector instead of the new one, then we need a second test.
+      That's why I check if the SideDefs facing each other are bound to
+      the same Sector.
+
+   Other note from RQ:
+      Nowadays, what makes the power of a good editor is its automatic tests.
+      So, if you are writing another Doom editor, you will probably want
+      to do the same kind of tests in your program.  Fine, but if you use
+      these ideas, don't forget to credit DEU...  Just a reminder... :-)
+*/
+
+/* now check if all SideDefs are facing a sidedef with the same Sector number */
+for (n = 0; n < NumLineDefs; n++)
+   {
+   ObjectsNeeded (OBJ_LINEDEFS, 0);
+   sd = LineDefs[n].sidedef1;
+   if (sd >= 0)
+      {
+      s = GetOppositeSector (n, 1);
+      ObjectsNeeded (OBJ_SIDEDEFS, 0);
+      if (s < 0 || SideDefs[sd].sector != s)
+	 {
+	 if (s < 0)
+	    {
+	    sprintf (msg1, "Sector #%d is not closed!", SideDefs[sd].sector);
+	    sprintf (msg2, "Check linedef #%d (first sidedef: #%d)", n, sd);
+	    }
+	 else
+	    {
+	    sprintf (msg1, "Sectors #%d and #%d are not closed!",
+	       SideDefs[sd].sector, s);
+	    sprintf (msg2, "Check linedef #%d (first sidedef: #%d)"
+	       " and the one facing it", n, sd);
+	    }
+	 if (CheckFailed (-1, -1, msg1, msg2, 0, first_time))
+	    {
+	    GoToObject (Objid (OBJ_LINEDEFS, n));
+	    return;
+	    }
+	 }
+      }
+   ObjectsNeeded (OBJ_LINEDEFS, 0);
+   sd = LineDefs[n].sidedef2;
+   if (sd >= 0)
+      {
+      s = GetOppositeSector (n, 0);
+      ObjectsNeeded (OBJ_SIDEDEFS, 0);
+      if (s < 0 || SideDefs[sd].sector != s)
+	 {
+	 if (s < 0)
+	    {
+	    sprintf (msg1, "Sector #%d is not closed!", SideDefs[sd].sector);
+	    sprintf (msg2, "Check linedef #%d (second sidedef: #%d)", n, sd);
+	    }
+	 else
+	    {
+	    sprintf (msg1, "Sectors #%d and #%d are not closed!",
+	       SideDefs[sd].sector, s);
+	    sprintf (msg2, "Check linedef #%d (second sidedef: #%d)"
+	       " and the one facing it", n, sd);
+	    }
+	 if (CheckFailed (-1, -1, msg1, msg2, 0, first_time))
+	    {
+	    GoToObject (Objid (OBJ_LINEDEFS, n));
+	    return;
+	    }
+	 }
+      }
+   }
+}
+
+
+/*
+   check cross-references and delete unused objects
+*/
+
+void CheckCrossReferences () /* SWAP! */
+{
+char   msg[80];
+int    n, m;
+SelPtr cur;
+bool   first_time = true;
+
+CheckingObjects ();
+LogMessage ("\nVerifying cross-references...\n");
+ObjectsNeeded (OBJ_LINEDEFS, 0);
+for (n = 0; n < NumLineDefs; n++)
+   {
+   /* Check for missing first sidedefs */
+   if (LineDefs[n].sidedef1 < 0)
+      {
+      sprintf (msg, "ERROR: linedef #%d has no first sidedef!", n);
+      CheckFailed (-1, -1, msg, 0, 1, first_time);
+      GoToObject (Objid (OBJ_LINEDEFS, n));
+      return;
+      }
+
+// FIXME should make this a mere warning
+#ifdef OLD  /* ifdef'd out AYM 19970725, I do it and it works */
+   /* Check for sidedefs used twice in the same linedef */
+   if (LineDefs[n].sidedef1 == LineDefs[n].sidedef2)
+      {
+      sprintf (msg, "ERROR: linedef #%d uses the same sidedef twice (#%d)",
+	n, LineDefs[n].sidedef1);
+      CheckFailed (-1, -1, msg, 0, 1, first_time);
+      GoToObject (Objid (OBJ_LINEDEFS, n));
+      return;
+      }
+#endif
+
+   /* Check for vertices used twice in the same linedef */
+   if (LineDefs[n].start == LineDefs[n].end)
+      {
+      sprintf (msg, "ERROR: linedef #%d uses the same vertex twice (#%d)",
+	n, LineDefs[n].start);
+      CheckFailed (-1, -1, msg, 0, 1, first_time);
+      GoToObject (Objid (OBJ_LINEDEFS, n));
+      return;
+      }
+   }
+
+/* check if there aren't two linedefs between the same Vertices */
+cur = 0;
+/* AYM 19980203 FIXME should use new algorithm */
+for (n = NumLineDefs - 1; n >= 1; n--)
+   {
+   for (m = n - 1; m >= 0; m--)
+      if ((LineDefs[n].start == LineDefs[m].start
+	&& LineDefs[n].end   == LineDefs[m].end)
+       || (LineDefs[n].start == LineDefs[m].end
+	&& LineDefs[n].end   == LineDefs[m].start))
+          {
+	  SelectObject (&cur, n);
+	  break;
+          }
+   }
+if (cur
+  && (Expert
+   || Confirm (-1, -1, "There are multiple linedefs between the same vertices",
+	   "Do you want to delete the redundant linedefs?")))
+   DeleteObjects (OBJ_LINEDEFS, &cur);
+else
+   ForgetSelection (&cur);
+
+CheckingObjects ();
+/* check for invalid flags in the linedefs */
+for (n = 0; n < NumLineDefs; n++)
+   if ((LineDefs[n].flags & 0x01) == 0 && LineDefs[n].sidedef2 < 0)
+      SelectObject (&cur, n);
+if (cur && (Expert
+    || Confirm (-1, -1, "Some linedefs have only one side but their I flag is"
+	" not set",
+        "Do you want to set the 'Impassible' flag?")))
+   while (cur)
+      {
+      LogMessage  ("Check: 1-sided linedef without I flag: %d", cur->objnum);
+      LineDefs[cur->objnum].flags |= 0x01;
+      UnSelectObject (&cur, cur->objnum);
+      }
+else
+   ForgetSelection (&cur);
+
+CheckingObjects ();
+for (n = 0; n < NumLineDefs; n++)
+   if ((LineDefs[n].flags & 0x04) != 0 && LineDefs[n].sidedef2 < 0)
+      SelectObject (&cur, n);
+if (cur
+  && (Expert
+      || Confirm (-1, -1, "Some linedefs have only one side but their 2 flag"
+	  " is set",
+	   "Do you want to clear the 'two-sided' flag?")))
+   {
+   while (cur)
+      {
+      LogMessage  ("Check: 1-sided linedef with 2s bit: %d", cur->objnum);
+      LineDefs[cur->objnum].flags &= ~0x04;
+      UnSelectObject (&cur, cur->objnum);
+      }
+   }
+else
+   ForgetSelection (&cur);
+
+CheckingObjects ();
+for (n = 0; n < NumLineDefs; n++)
+   if ((LineDefs[n].flags & 0x04) == 0 && LineDefs[n].sidedef2 >= 0)
+      SelectObject (&cur, n);
+if (cur
+  && (Expert
+      || Confirm (-1, -1,
+	   "Some linedefs have two sides but their 2S bit is not set",
+	   "Do you want to set the 'two-sided' flag?")))
+   {
+   while (cur)
+      {
+      LineDefs[cur->objnum].flags |= 0x04;
+      UnSelectObject (&cur, cur->objnum);
+      }
+   }
+else
+   ForgetSelection (&cur);
+
+CheckingObjects ();
+/* select all Vertices */
+for (n = 0; n < NumVertices; n++)
+   SelectObject (&cur, n);
+/* unselect Vertices used in a LineDef */
+for (n = 0; n < NumLineDefs; n++)
+   {
+   m = LineDefs[n].start;
+   if (cur && m >= 0)
+      UnSelectObject (&cur, m);
+   m = LineDefs[n].end;
+   if (cur && m >= 0)
+      UnSelectObject (&cur, m);
+   continue;
+   }
+/* check if there are any Vertices left */
+if (cur
+  && (Expert
+     || Confirm (-1, -1, "Some vertices are not bound to any linedef",
+			"Do you want to delete these unused Vertices?")))
+   {
+   DeleteObjects (OBJ_VERTICES, &cur);
+   ObjectsNeeded (OBJ_LINEDEFS, 0);
+   }
+else
+   ForgetSelection (&cur);
+
+CheckingObjects ();
+/* select all SideDefs */
+for (n = 0; n < NumSideDefs; n++)
+   SelectObject (&cur, n);
+/* unselect SideDefs bound to a LineDef */
+for (n = 0; n < NumLineDefs; n++)
+   {
+   m = LineDefs[n].sidedef1;
+   if (cur && m >= 0)
+      UnSelectObject (&cur, m);
+   m = LineDefs[n].sidedef2;
+   if (cur && m >= 0)
+      UnSelectObject (&cur, m);
+   continue;
+   }
+/* check if there are any SideDefs left */
+if (cur
+  && (Expert
+      || Confirm (-1, -1, "Some sidedefs are not bound to any linedef",
+			 "Do you want to delete these unused sidedefs?")))
+   DeleteObjects (OBJ_SIDEDEFS, &cur);
+else
+   ForgetSelection (&cur);
+
+CheckingObjects ();
+/* select all Sectors */
+for (n = 0; n < NumSectors; n++)
+   SelectObject (&cur, n);
+/* unselect Sectors bound to a sidedef */
+for (n = 0; n < NumLineDefs; n++)
+   {
+   ObjectsNeeded (OBJ_LINEDEFS, 0);
+   m = LineDefs[n].sidedef1;
+   ObjectsNeeded (OBJ_SIDEDEFS, 0);
+   if (cur && m >= 0 /* && SideDefs[m].sector >= 0 AYM 1998-06-13 */)
+      UnSelectObject (&cur, SideDefs[m].sector);
+   ObjectsNeeded (OBJ_LINEDEFS, 0);
+   m = LineDefs[n].sidedef2;
+   ObjectsNeeded (OBJ_SIDEDEFS, 0);
+   if (cur && m >= 0 /* && SideDefs[m].sector >= 0 AYM 1998-06-13 */)
+      UnSelectObject (&cur, SideDefs[m].sector);
+   continue;
+   }
+/* check if there are any Sectors left */
+if (cur
+ && (Expert
+     || Confirm (-1, -1, "Some sectors are not bound to any sidedef",
+			"Do you want to delete these unused sectors?")))
+   DeleteObjects (OBJ_SECTORS, &cur);
+else
+   ForgetSelection (&cur);
+}
+
+
+/*
+   check for missing textures
+*/
+
+void CheckTextures () /* SWAP! */
+{
+int  n;
+int  sd1, sd2;
+int  s1, s2;
+char msg1[80], msg2[80];
+bool first_time = true;
+
+CheckingObjects ();
+LogMessage ("\nVerifying textures...\n");
+ObjectsNeeded (OBJ_SECTORS, 0);
+for (n = 0; n < NumSectors; n++)
+   {
+   if (strcmp (Sectors[n].ceilt, "-") == 0
+     || strcmp (Sectors[n].ceilt, "") == 0
+     || memcmp (Sectors[n].ceilt, "        ", 8) == 0)
+      {
+      sprintf (msg1, "Error: sector #%d has no ceiling texture", n);
+      sprintf (msg2, "You probably used a brain-damaged editor to do that...");
+      CheckFailed (-1, -1, msg1, msg2, 1, first_time);
+      GoToObject (Objid (OBJ_SECTORS, n));
+      return;
+      }
+   if (strcmp (Sectors[n].floort, "-") == 0
+     || strcmp (Sectors[n].floort, "") == 0
+     || memcmp (Sectors[n].floort, "        ", 8) == 0)
+      {
+      sprintf (msg1, "Error: sector #%d has no floor texture", n);
+      sprintf (msg2, "You probably used a brain-damaged editor to do that...");
+      CheckFailed (-1, -1, msg1, msg2, 1, first_time);
+      GoToObject (Objid (OBJ_SECTORS, n));
+      return;
+      }
+   if (Sectors[n].ceilh < Sectors[n].floorh)
+      {
+      sprintf (msg1,
+	"Error: sector #%d has its ceiling lower than its floor", n);
+      sprintf (msg2,
+	"The textures will never be displayed if you cannot go there");
+      CheckFailed (-1, -1, msg1, msg2, 1, first_time);
+      GoToObject (Objid (OBJ_SECTORS, n));
+      return;
+      }
+#if 0  /* AYM 2000-08-13 */
+   if (Sectors[n].ceilh - Sectors[n].floorh > 1023)
+      {
+      sprintf (msg1, "Error: sector #%d has its ceiling too high", n);
+      sprintf (msg2, "The maximum difference allowed is 1023 (ceiling - floor)");
+      CheckFailed (-1, -1, msg1, msg2, 1, first_time);
+      GoToObject (Objid (OBJ_SECTORS, n));
+      return;
+      }
+#endif
+   }
+
+for (n = 0; n < NumLineDefs; n++)
+   {
+   ObjectsNeeded (OBJ_LINEDEFS, 0);
+   sd1 = LineDefs[n].sidedef1;
+   sd2 = LineDefs[n].sidedef2;
+   ObjectsNeeded (OBJ_SIDEDEFS, OBJ_SECTORS, 0);
+   if (sd1 >= 0)
+      s1 = SideDefs[sd1].sector;
+   else
+      s1 = OBJ_NO_NONE;
+   if (sd2 >= 0)
+      s2 = SideDefs[sd2].sector;
+   else
+      s2 = OBJ_NO_NONE;
+   if (is_obj (s1) && ! is_obj (s2))
+      {
+      if (SideDefs[sd1].tex3[0] == '-' && SideDefs[sd1].tex3[1] == '\0')
+	 {
+	 sprintf (msg1, "Error in one-sided linedef #%d:"
+	   " sidedef #%d has no middle texture", n, sd1);
+	 sprintf (msg2, "Do you want to set the texture to \"%s\""
+	   " and continue?", default_middle_texture);
+	 if (CheckFailed (-1, -1, msg1, msg2, 0, first_time))
+	    {
+	    GoToObject (Objid (OBJ_LINEDEFS, n));
+	    return;
+	    }
+	 strncpy (SideDefs[sd1].tex3, default_middle_texture, WAD_TEX_NAME);
+         MadeChanges = 1;
+	 CheckingObjects ();
+	 }
+      }
+   if (is_obj (s1) && is_obj (s2) && Sectors[s1].ceilh > Sectors[s2].ceilh)
+      {
+      if (SideDefs[sd1].tex1[0] == '-' && SideDefs[sd1].tex1[1] == '\0'
+	  && (! is_sky (Sectors[s1].ceilt) || ! is_sky (Sectors[s2].ceilt)))
+	 {
+	 sprintf (msg1, "Error in first sidedef of linedef #%d:"
+	   " sidedef #%d has no upper texture", n, sd1);
+	 sprintf (msg2, "Do you want to set the texture to \"%s\""
+	   " and continue?", default_upper_texture);
+	 if (CheckFailed (-1, -1, msg1, msg2, 0, first_time))
+	    {
+	    GoToObject (Objid (OBJ_LINEDEFS, n));
+	    return;
+	    }
+	 strncpy (SideDefs[sd1].tex1, default_upper_texture, WAD_TEX_NAME);
+         MadeChanges = 1;
+	 CheckingObjects ();
+	 }
+      }
+   if (is_obj (s1) && is_obj (s2) && Sectors[s1].floorh < Sectors[s2].floorh)
+      {
+      if (SideDefs[sd1].tex2[0] == '-' && SideDefs[sd1].tex2[1] == '\0')
+	 {
+	 sprintf (msg1, "Error in first sidedef of linedef #%d:"
+	   " sidedef #%d has no lower texture", n, sd1);
+	 sprintf (msg2, "Do you want to set the texture to \"%s\""
+	   " and continue?", default_lower_texture);
+	 if (CheckFailed (-1, -1, msg1, msg2, 0, first_time))
+	    {
+	    GoToObject (Objid (OBJ_LINEDEFS, n));
+	    return;
+	    }
+	 strncpy (SideDefs[sd1].tex2, default_lower_texture, WAD_TEX_NAME);
+         MadeChanges = 1;
+	 CheckingObjects ();
+	 }
+      }
+   if (is_obj (s1) && is_obj (s2) && Sectors[s2].ceilh > Sectors[s1].ceilh)
+      {
+      if (SideDefs[sd2].tex1[0] == '-' && SideDefs[sd2].tex1[1] == '\0'
+	  && (! is_sky (Sectors[s1].ceilt) || ! is_sky (Sectors[s2].ceilt)))
+	 {
+	 sprintf (msg1, "Error in second sidedef of linedef #%d:"
+	   " sidedef #%d has no upper texture", n, sd2);
+	 sprintf (msg2, "Do you want to set the texture to \"%s\""
+	   " and continue?", default_upper_texture);
+	 if (CheckFailed (-1, -1, msg1, msg2, 0, first_time))
+	    {
+	    GoToObject (Objid (OBJ_LINEDEFS, n));
+	    return;
+	    }
+	 strncpy (SideDefs[sd2].tex1, default_upper_texture, WAD_TEX_NAME);
+         MadeChanges = 1;
+	 CheckingObjects ();
+	 }
+      }
+   if (is_obj (s1) && is_obj (s2) && Sectors[s2].floorh < Sectors[s1].floorh)
+      {
+      if (SideDefs[sd2].tex2[0] == '-' && SideDefs[sd2].tex2[1] == '\0')
+	 {
+	 sprintf (msg1, "Error in second sidedef of linedef #%d:"
+	   " sidedef #%d has no lower texture", n, sd2);
+	 sprintf (msg2, "Do you want to set the texture to \"%s\""
+	   " and continue?", default_lower_texture);
+	 if (CheckFailed (-1, -1, msg1, msg2, 0, first_time))
+	    {
+	    GoToObject (Objid (OBJ_LINEDEFS, n));
+	    return;
+	    }
+	 strncpy (SideDefs[sd2].tex2, default_lower_texture, WAD_TEX_NAME);
+         MadeChanges = 1;
+	 CheckingObjects ();
+	 }
+      }
+   }
+}
+
+
+/*
+   check if a texture name matches one of the elements of a list
+*/
+
+bool IsTextureNameInList (char *name, char **list, int numelems)
+{
+int n;
+
+for (n = 0; n < numelems; n++)
+   if (! y_strnicmp (name, list[n], WAD_TEX_NAME))
+      return true;
+return false;
+}
+
+
+/*
+   check for invalid texture names
+*/
+
+void CheckTextureNames () /* SWAP! */
+{
+int  n;
+char msg1[80], msg2[80];
+bool first_time = true;
+
+CheckingObjects ();
+LogMessage ("\nVerifying texture names...\n");
+
+// AYM 2000-07-24: could someone explain this one ?
+if (! FindMasterDir (MasterDir, "F2_START"))
+   NumThings--;
+
+ObjectsNeeded (OBJ_SECTORS, 0);
+for (n = 0; n < NumSectors; n++)
+   {
+   if (! is_flat_name_in_list (Sectors[n].ceilt))
+      {
+      sprintf (msg1, "Invalid ceiling texture in sector #%d", n);
+      sprintf (msg2, "The name \"%.*s\" is not a floor/ceiling texture",
+	(int) WAD_FLAT_NAME, Sectors[n].ceilt);
+      if (CheckFailed (-1, -1, msg1, msg2, 0, first_time))
+	 {
+	 GoToObject (Objid (OBJ_SECTORS, n));
+	 return;
+	 }
+      CheckingObjects ();
+      }
+   if (! is_flat_name_in_list (Sectors[n].floort))
+      {
+      sprintf (msg1, "Invalid floor texture in sector #%d", n);
+      sprintf (msg2, "The name \"%.*s\" is not a floor/ceiling texture",
+	(int) WAD_FLAT_NAME, Sectors[n].floort);
+      if (CheckFailed (-1, -1, msg1, msg2, 0, first_time))
+	 {
+	 GoToObject (Objid (OBJ_SECTORS, n));
+	 return;
+	 }
+      CheckingObjects ();
+      }
+   }
+ObjectsNeeded (OBJ_SIDEDEFS, 0);
+for (n = 0; n < NumSideDefs; n++)
+   {
+   if (! IsTextureNameInList (SideDefs[n].tex1, WTexture, NumWTexture))
+      {
+      sprintf (msg1, "Invalid upper texture in sidedef #%d", n);
+      sprintf (msg2, "The name \"%.*s\" is not a wall texture",
+	(int) WAD_TEX_NAME, SideDefs[n].tex1);
+      if (CheckFailed (-1, -1, msg1, msg2, 0, first_time))
+	 {
+	 GoToObject (Objid (OBJ_SIDEDEFS, n));
+	 return;
+	 }
+      CheckingObjects ();
+      }
+   if (! IsTextureNameInList (SideDefs[n].tex2, WTexture, NumWTexture))
+      {
+      sprintf (msg1, "Invalid lower texture in sidedef #%d", n);
+      sprintf (msg2, "The name \"%.*s\" is not a wall texture",
+	(int) WAD_TEX_NAME, SideDefs[n].tex2);
+      if (CheckFailed (-1, -1, msg1, msg2, 0, first_time))
+	 {
+	 GoToObject (Objid (OBJ_SIDEDEFS, n));
+	 return;
+	 }
+      CheckingObjects ();
+      }
+   if (! IsTextureNameInList (SideDefs[n].tex3, WTexture, NumWTexture))
+      {
+      sprintf (msg1, "Invalid middle texture in sidedef #%d", n);
+      sprintf (msg2, "The name \"%.*s\" is not a wall texture",
+	(int) WAD_TEX_NAME, SideDefs[n].tex3);
+      if (CheckFailed (-1, -1, msg1, msg2, 0, first_time))
+	 {
+	 GoToObject (Objid (OBJ_SIDEDEFS, n));
+	 return;
+	 }
+      CheckingObjects ();
+      }
+   }
+}
+
+
+/*
+   check for players starting points
+*/
+
+bool CheckStartingPos () /* SWAP! */
+{
+char msg1[80], msg2[80];
+bool p1 = false;
+bool p2 = false;
+bool p3 = false;
+bool p4 = false;
+size_t dm = 0;
+int  t;
+
+ObjectsNeeded (OBJ_THINGS, 0);
+for (t = 0; t < NumThings; t++)
+   {
+   if (Things[t].type == THING_PLAYER1)
+      p1 = true;
+   if (Things[t].type == THING_PLAYER2)
+      p2 = true;
+   if (Things[t].type == THING_PLAYER3)
+      p3 = true;
+   if (Things[t].type == THING_PLAYER4)
+      p4 = true;
+   if (Things[t].type == THING_DEATHMATCH)
+      dm++;
+   }
+if (! p1)
+   {
+   Beep ();
+   if (! Confirm (-1, -1, "Warning: there is no player 1 starting point. The"
+       " game", "will crash if you play with this level. Save anyway ?"))
+      return false;
+   else 
+      return true;  // No point in doing further checking !
+   }
+if (Expert)
+   return true;
+if (! p2 || ! p3 || ! p4)
+   {
+   if (! p4)
+     t = 4;
+   if (! p3)
+     t = 3;
+   if (! p2)
+     t = 2;
+   sprintf (msg1, "Warning: there is no player %d start."
+     " You will not be able", t);
+   sprintf (msg2, "to use this level for multi-player games."
+     " Save anyway ?");
+   if (! Confirm (-1, -1, msg1, msg2))
+      return false;
+   else
+      return true;  // No point in doing further checking !
+   }
+if (dm < DOOM_MIN_DEATHMATCH_STARTS)
+   {
+   if (dm == 0)
+     sprintf (msg1, "Warning: there are no deathmatch starts."
+       " You need at least %d", DOOM_MIN_DEATHMATCH_STARTS);
+   else if (dm == 1)
+     sprintf (msg1, "Warning: there is only one deathmatch start."
+       " You need at least %d", DOOM_MIN_DEATHMATCH_STARTS);
+   else
+     sprintf (msg1, "Warning: there are only %d deathmatch starts."
+       " You need at least %d", dm, DOOM_MIN_DEATHMATCH_STARTS);
+   sprintf (msg2, "deathmatch starts to play deathmatch games."
+     " Save anyway ?");
+   if (! Confirm (-1, -1, msg1, msg2))
+     return false;
+   }
+return true;
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/checks.h	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,14 @@
+/*
+ *	checks.h
+ *	AYM 1998-12-02
+ */
+
+
+void CheckLevel (int x0, int y0);
+void Statistics ();
+void CheckSectors ();
+void CheckCrossReferences ();
+void CheckTextures ();
+void CheckTextureNames ();
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/colour.h	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,34 @@
+/*
+ *	colour.h
+ *	AYM 1998-11-28
+ */
+
+
+#ifndef YH_COLOUR  // Prevent multiple inclusion
+#define YH_COLOUR  // Prevent multiple inclusion
+
+class rgb_c;
+
+/* pcolour_t -- a physical colour number.
+   The value of a pixel in the opinion of the output library.
+   The exact size and meaning of this type vary.
+   With X DirectColor visuals, it's an RGB value.
+   With X PseudoColor visuals and BGI 256-colour modes,
+   it's a palette index.
+   With BGI 16-colour modes, it's an IRGB value. */
+
+#if defined Y_BGI
+typedef i16 pcolour_t;			// BGI: up to 8 BPP.
+#define PCOLOUR_NONE  0xffff		/* An "impossible" colour no. */
+#elif defined Y_X11
+typedef unsigned long pcolour_t;	// X11: up to 32 BPP.
+#define PCOLOUR_NONE  0xffffffff	/* An "impossible" colour no. */
+#endif
+
+pcolour_t *alloc_colours (rgb_c rgb_values[], size_t count);
+void free_colours (pcolour_t *pc, size_t count);
+size_t get_pcolours_count ();
+pcolour_t get_pcolour_pcn (size_t i);
+
+#endif	// Prevent multiple inclusions
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/colour1.cc	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,95 @@
+/*
+ *	colour1.cc
+ *	getcolour()
+ *	AYM 1998-01-27
+ */
+
+
+/*
+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 "rgb.h"
+
+
+#define RGB_DIGITS 2  /* R, G and B are 8-bit wide each */
+
+
+/*
+ *	getcolour
+ *	Decode an "rgb:<r>/<g>/<b>" colour specification
+ *	Returns :
+ *	  0    OK
+ *	  <>0  malformed colour specification
+ */
+int getcolour (const char *s, rgb_c *rgb)
+{
+  int i;
+  int digit;
+  int rdigits;
+  int gdigits;
+  int bdigits;
+  unsigned r;
+  unsigned g;
+  unsigned b;
+  int globaldigits;
+
+  if (strncmp (s, "rgb:", 4))
+    return 1;
+
+  for (i = 4, r = 0, rdigits = 0; (digit = hextoi (s[i])) >= 0; i++, rdigits++)
+    r = (r << 4) | digit;
+  if (s[i++] != '/')
+    return 2;
+
+  for (g = 0, gdigits = 0; (digit = hextoi (s[i])) >= 0; i++, gdigits++)
+    g = (g << 4) | digit;
+  if (s[i++] != '/')
+    return 3;
+    
+  for (b = 0, bdigits = 0; (digit = hextoi (s[i])) >= 0; i++, bdigits++)
+    b = (b << 4) | digit;
+  if (s[i++] != '\0')
+    return 4;
+
+  // Force to 8 bits (RGB_DIGITS hex digits) by scaling up or down
+  globaldigits = rdigits;
+  globaldigits = y_max (globaldigits, gdigits);
+  globaldigits = y_max (globaldigits, bdigits);
+  for (; globaldigits < RGB_DIGITS; globaldigits++)
+  {
+    r <<= 4;
+    g <<= 4;
+    b <<= 4;
+  }
+  for (; globaldigits > RGB_DIGITS; globaldigits--)
+  {
+    r >>= 4;
+    g >>= 4;
+    b >>= 4;
+  }
+  rgb->set (r, g, b);
+  return 0;
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/colour2.cc	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,47 @@
+/*
+ *	colour2.cc
+ *	rgb2irgb()
+ *	AYM 1998-06-28
+ */
+
+
+/*
+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"
+
+
+/*
+ *	rgb2irgb
+ *	Convert an RGB colour to an IRGB (16-colour VGA) colour.
+ */
+int rgb2irgb (int r, int g, int b)
+{
+  int c;
+
+  c = 4*!!r + 2*!!g + 1*!!b;
+  if (r > 128 || g > 128 || b > 128)
+    c += 8;  // Set high intensity bit
+  return c;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/colour3.cc	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,51 @@
+/*
+ *	colour3.cc
+ *	irgb2rgb()
+ *	AYM 1998-06-28
+ */
+
+
+/*
+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 "rgb.h"
+
+
+/*
+ *	irgb2rgb
+ *	Convert an IRGB colour (16-colour VGA) to an 8-bit-per-component
+ *	RGB colour.
+ */
+void irgb2rgb (int c, rgb_c *rgb)
+{
+  if (c == 8)  // Special case for DARKGREY
+    rgb->r = rgb->g = rgb->b = 0x40;
+  else
+  {
+    rgb->r = (c & 4) ? ((c & 8) ? 0xff : 0x80) : 0;
+    rgb->g = (c & 2) ? ((c & 8) ? 0xff : 0x80) : 0;
+    rgb->b = (c & 1) ? ((c & 8) ? 0xff : 0x80) : 0;
+  }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/colour4.cc	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,301 @@
+/*
+ *	colour4.cc
+ *	Allocate and free physical colours.
+ *	AYM 1998-11-27
+ */
+
+
+/*
+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"
+#ifdef Y_X11
+#include <X11/Xlib.h>
+#endif
+#include "colour.h"
+#include "gfx.h"
+#include "rgb.h"
+#include "x11.h"
+
+
+/* This table contains all the physical colours allocated,
+   with their rgb value and usage count. */
+typedef struct 
+{
+  pcolour_t pcn;	// The physical colour# (pixel value).
+  rgb_c rgb;		// Its RGB value.
+  int usage_count;	// Number of logical colours that use it.
+} pcolours_table_entry_t;
+pcolours_table_entry_t *pcolours = 0;
+size_t physical_colours = 0;  // Number of entries in <pcolours>
+
+
+static void dump_pcolours ();
+
+
+/*
+ *	eight2sixteen
+ *	Convert an 8-bit RGB component value to a 16-bit one.
+ *	Will convert 00h to 0000h, 80h to 8080h and FFh to FFFFh.
+ */
+inline u16 eight2sixteen (u8 v)
+{
+  return (v << 8) | v;
+}
+
+
+/*
+ *	alloc_colours
+ *	Allocate a group of <count> rgb values and return an array of
+ *	<count> physical colour numbers.
+ */
+pcolour_t *alloc_colours (rgb_c rgb_values[], size_t count)
+{
+  verbmsg ("colours: alloc_colours: count %d\n", count);
+
+  pcolour_t *pcn_table = (pcolour_t *) malloc (count * sizeof *pcn_table);
+  if (pcn_table == NULL)
+    fatal_error (msg_nomem);
+
+  /* Allocate the physical colours if necessary. Should not do
+     it for static visuals (StaticColor, TrueColor). It does no
+     harm but it's useless. */
+  for (size_t n = 0; n < count; n++)
+  {
+    // Is there already a physical colour for this RGB value ?
+    pcn_table[n] = PCOLOUR_NONE;
+    for (size_t i = 0; i < physical_colours; i++)
+    {
+      if (pcolours[i].rgb == rgb_values[n])
+      {
+	// There is. Reuse it.
+	pcn_table[n] = pcolours[i].pcn;
+	pcolours[i].usage_count++;
+	break;
+      }
+    }
+
+    // There isn't. Try to create a new physical colour.
+    if (pcn_table[n] == PCOLOUR_NONE)
+    {
+      XColor xc;
+      xc.red   = eight2sixteen (rgb_values[n].r);
+      xc.green = eight2sixteen (rgb_values[n].g);
+      xc.blue  = eight2sixteen (rgb_values[n].b);
+      Status r = XAllocColor (dpy, cmap, &xc);
+
+      /* Allocation successful. Add a new entry to
+	 the table of physical colours. */
+      if (r != 0)
+      {
+	pcn_table[n] = (pcolour_t) xc.pixel;
+	physical_colours++;
+	pcolours = (pcolours_table_entry_t *)
+	  realloc (pcolours, physical_colours * sizeof *pcolours);
+	if (pcolours == NULL)
+	  fatal_error (msg_nomem);
+	pcolours[physical_colours - 1].pcn         = (pcolour_t) xc.pixel;
+	pcolours[physical_colours - 1].rgb         = rgb_values[n];
+	pcolours[physical_colours - 1].usage_count = 1;
+      }
+
+      /* Couldn't allocate (the colormap is full).
+	 Reuse the nearest existing physical colour. */
+      else
+      {
+	size_t best_fit = 0;
+	int best_delta = INT_MAX;
+	
+	for (size_t m = 0; m < physical_colours; m++)
+	{
+	  int delta = pcolours[m].rgb - rgb_values[n];
+	  if (delta < best_delta)
+	  {
+	    best_fit = m;
+	    best_delta = delta;
+	  }
+	}
+	verbmsg ("colours: alloc_colours %d/%d/%d: reused %d/%d/%d, delta=%d\n",
+	   rgb_values[n].r, rgb_values[n].g, rgb_values[n].b, 
+	   pcolours[best_fit].rgb.r, pcolours[best_fit].rgb.g,
+	   pcolours[best_fit].rgb.b,
+	   best_delta);
+	pcn_table[n] = pcolours[best_fit].pcn;
+	pcolours[best_fit].usage_count++;
+      }
+    }
+  }
+  return pcn_table;
+}
+
+
+/*
+ *	free_colours
+ *	Free the <count> physical colours in <pc>.
+ */
+void free_colours (pcolour_t *pcn_table, size_t count)
+{
+  verbmsg ("colours: free_colours: count %d\n", count);
+  if (verbose)
+    dump_pcolours ();
+
+  if (pcn_table == NULL)  // Sanity
+    return;
+
+  /* Decrement the usage count for all those physical colours.
+     If the usage count reaches 0, actually free them. */
+  for (pcolour_t *pcn = pcn_table; count; count--, pcn++)
+  {
+    size_t i;
+
+    for (i = 0; i < physical_colours; i++)
+      if (pcolours[i].pcn == *pcn)
+	break;
+    
+    if (i == physical_colours)
+      fatal_error ("Trying to free pc[%d]=%ld that does not exist",
+	(int) i, (long) *pcn);
+
+    if (pcolours[i].usage_count < 1)
+      fatal_error ("Freeing unused colour %ld", (long) *pcn);
+
+    pcolours[i].usage_count--;
+    if (pcolours[i].usage_count == 0)
+    {
+      unsigned long pixel = (unsigned long) *pcn;
+      x_catch_on ();
+      XFreeColors (dpy, cmap, &pixel, 1, 0);
+      // Should not happen but sometimes does (not reproducible)
+      if (const char *err_msg = x_error ())
+	warn ("error freeing colour %08lXh (%s).\n", pixel, err_msg);
+      x_catch_off ();
+      pcolours[i].pcn = PCOLOUR_NONE;
+    }
+  }
+
+  /* If physical colours have actually been freed,
+     remove them from the table of physical colours. */
+  size_t new_physical_colours = 0;
+
+  {
+    for (size_t i = 0; i < physical_colours; i++)
+      if (pcolours[i].pcn != PCOLOUR_NONE)
+	new_physical_colours++;  // Number of physical colours still in use.
+  }
+
+  verbmsg ("colours: freed %d of %d physical colours\n",
+    physical_colours - new_physical_colours, physical_colours);
+
+  if (new_physical_colours == 0)
+  {
+    free (pcolours);
+    pcolours = 0;
+  }
+  else
+  {
+    pcolours_table_entry_t *new_item;
+    pcolours_table_entry_t *new_pcolours = (pcolours_table_entry_t *)
+      malloc (new_physical_colours * sizeof *new_pcolours);
+    if (new_pcolours == NULL)
+      fatal_error (msg_nomem);
+    new_item = new_pcolours;
+    for (size_t i = 0; i < physical_colours; i++)
+      if (pcolours[i].pcn != PCOLOUR_NONE)
+	memcpy (new_item++, pcolours + i, sizeof *new_pcolours);
+    free (pcolours);
+    pcolours = new_pcolours;
+  }
+  physical_colours = new_physical_colours;
+
+  //if (verbose)
+  //   dump_pcolours ();
+
+  free (pcn_table);
+}
+
+
+/*
+ *	get_pcolours_count
+ *	Return the number of physical colours allocated
+ */
+size_t get_pcolours_count ()
+{
+  return physical_colours;
+}
+
+
+/*
+ *	get_pcolour_pcn
+ *	Return the physical colour number (a.k.a. pixel value)
+ *	for the <i>th physical colour allocated.
+ */
+pcolour_t get_pcolour_pcn (size_t i)
+{
+  if (i >= physical_colours)
+  {
+    nf_bug ("get_pcolour_pcn: i=%d\n", (int) i);
+    return ULONG_MAX;
+  }
+  return pcolours[i].pcn;
+}
+
+
+/*
+ *	dump_pcolours
+ *	For debugging purposes
+ */
+static void dump_pcolours ()
+{
+  int items_on_current_line = 0;
+
+  for (size_t i = 0; i < physical_colours; i++)
+  {
+#if 0
+    printf ("%02lX %02X/%02X/%02X %d",
+       pcolours[i].pcn,
+       pcolours[i].rgb.r,
+       pcolours[i].rgb.g,
+       pcolours[i].rgb.b,
+       pcolours[i].usage_count);
+    fputs (i % 5 == 4 ? "\n" : "  ", stdout);
+#endif
+    if (items_on_current_line == 0)
+      verbmsg ("colours: ");
+    verbmsg ("%c",
+	(pcolours[i].usage_count == 1) ? '.' : '0' + pcolours[i].usage_count);
+    if (++items_on_current_line % 10 == 0)
+    {
+      if (items_on_current_line == 50)
+      {
+	items_on_current_line = 0;
+	verbmsg ("\n");
+      }
+      else
+        verbmsg (" ");
+    }
+  }
+  if (items_on_current_line != 0)
+    verbmsg ("\n");
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/credits.cc	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,12 @@
+// DO NOT EDIT -- generated from docsrc/copyright
+
+extern const char *const yadex_copyright[] =
+{
+  "Parts copyright Andrew Apted 2000-2001, GNU GPL v2",
+  "Parts copyright André Majorel 1997-2003, GNU GPL v2",
+  "Parts copyright Matthew W. Miller 2000, GNU GPL v2",
+  "Parts written by Raphaël Quinet, public domain",
+  "Parts written by Brendon Wyber, public domain",
+  0
+};
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/credits.h	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,1 @@
+extern const char *const yadex_copyright[];
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/dependcy.cc	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,56 @@
+/*
+ *	dependcy.cc
+ *	Dependency class
+ *	AYM 2000-04-09
+ */
+
+
+/*
+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"  /* Just to force a recompile when you ./configure again */
+#include "dependcy.h"
+#include "serialnum.h"
+
+
+Dependency::Dependency (Serial_num *sn)
+{
+  serial_num  = sn;
+  token_valid = false;
+}
+
+
+bool Dependency::outdated ()
+{
+  if (! token_valid)
+    return true;
+  return serial_num->outdated (token);
+}
+
+
+void Dependency::update ()
+{
+  serial_num->update (token);
+  token_valid = true;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/dependcy.h	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,47 @@
+/*
+ *	dependcy.h
+ *	Dependency class
+ *	AYM 2000-04-09
+ */
+
+
+/* This class, along with the Serial_num class, allow one to
+   express a relationship of dependency (think makefiles)
+   between two objects. For the sake of discussion, let's assume
+   that class Target depends on class Source.
+
+   Make Source use a Serial_num object and make it call
+   Serial_num::bump() whenever it changes. Make Target use a
+   Dependency object. The Dependency object should be
+   constructed with a pointer to the Serial_num member of Source.
+
+   In all public methods of Target, start by checking whether
+   Source has been modified while we were out by calling
+   Dependency::outdated(). If the latter returns true, Target
+   shall update itself based on the new state of Source and then
+   call Dependency::update(). */
+
+
+#ifndef YH_DEPENDCY  /* DO NOT INSERT ANYTHING BEFORE THIS LINE */
+#define YH_DEPENDCY
+
+
+class Serial_num;			// Defined in serialnum.h
+typedef unsigned long serial_num_t;	// Copied from serialnum.h
+
+
+class Dependency
+{
+  public :
+    Dependency (Serial_num *sn);
+    bool outdated ();
+    void update ();
+
+  private :
+    Serial_num   *serial_num;
+    serial_num_t  token;
+    bool          token_valid;
+};
+
+
+#endif  /* DO NOT ADD ANYTHING AFTER THIS LINE */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/dialog.cc	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,239 @@
+/*
+ *	dialog.cc
+ *	Dialog boxes.
+ *	AYM 1998-11-30
+ */
+
+
+/*
+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 <X11/Xlib.h>
+#include "dialog.h"
+#include "gfx.h"
+
+
+/*
+ *	Confirm - ask for confirmation
+ *
+ *	Ask for confirmation (prompt2 may be NULL).
+ *
+ *	Return zero for "no", non-zero for "yes".
+ */
+bool Confirm (int x0, int y0, const char *prompt1, const char *prompt2)
+{
+  const char *const prompt3 = "Press [Y] to confirm, [N] to cancel...";
+  size_t maxlen;
+  double n_lines_of_text;
+  int width;
+  int height;
+  int text_x0;
+  int text_x1;
+  int x1;
+  int text_y0;
+  int text_y1;
+  int y1;
+  bool rc;
+
+  maxlen = strlen (prompt3);
+  if (strlen (prompt1) > maxlen)
+    maxlen = strlen (prompt1);
+  if (prompt2 != NULL && strlen (prompt2) > maxlen)
+    maxlen = strlen (prompt2);
+  n_lines_of_text = (prompt2 == NULL ? 2.5 : 3.5);
+  width = 2 * BOX_BORDER + 2 * WIDE_HSPACING + maxlen * FONTW;
+  height = 2 * BOX_BORDER + 2 * WIDE_VSPACING + (int) (n_lines_of_text * FONTH);
+  if (x0 < 0)
+    x0 = (ScrMaxX - width) / 2;
+  if (y0 < 0)
+    y0 = (ScrMaxY - height) / 2;
+  text_x0 = x0 + BOX_BORDER + WIDE_HSPACING;
+  text_x1 = text_x0 + maxlen * FONTW - 1;
+  x1      = text_x1 + WIDE_HSPACING + BOX_BORDER;
+  text_y0 = y0 + BOX_BORDER + WIDE_VSPACING;
+  text_y1 = text_y0 + (int) (n_lines_of_text * FONTH) - 1;
+  y1      = text_y1 + WIDE_HSPACING + BOX_BORDER;
+  HideMousePointer ();
+  for (bool first_time = true; ; first_time = false)
+  {
+    if (first_time || is.key == YE_EXPOSE)
+    {
+      DrawScreenBox3D (x0, y0, x1, y1);
+      set_colour (WHITE);
+      DrawScreenText (text_x0, text_y0, prompt1);
+      if (prompt2 != NULL)
+	DrawScreenText (text_x0, text_y0 + FONTH, prompt2);
+      set_colour (WINTITLE);
+      DrawScreenText (text_x0, text_y1 - FONTH - 1, prompt3);
+    }
+    get_input_status ();
+    if (is.key == 'y' || is.key == 'Y' || is.key == YK_RETURN)
+    {
+      rc = true;
+      break;
+    }
+    if (is.key == 'n' || is.key == 'N' || is.key == YK_ESC)
+    {
+      rc = false;
+      break;
+    }
+  }
+  is.key = 0;  // Shouldn't have to do that but EditorLoop() is broken
+  ShowMousePointer ();
+  return rc;
+}
+
+
+/*
+ *	Confirm2 - ask for confirmation, in a smarter fashion
+ *
+ *	Return zero for "no", non-zero for "yes".
+ */
+int Confirm2 (int x0, int y0, confirm_t *confirm_flag,
+   const char *prompt1, const char *prompt2)
+{
+  int r;
+
+  if (*confirm_flag == YC_YES)
+    return 1;
+  if (*confirm_flag == YC_NO)
+    return 0;
+  r = Confirm (x0, y0, prompt1, prompt2);
+  if (*confirm_flag == YC_ASK_ONCE)
+    *confirm_flag = r ? YC_YES : YC_NO;  // We won't ask again
+  return r;
+}
+
+
+/*
+ *	Notify - notification dialog box
+ *
+ *	Display a notification and wait for a key (prompt2 may
+ *	be NULL)
+ */
+void Notify (int x0, int y0, const char *prompt1, const char *prompt2)
+{
+  const char *const prompt3 = "Press any key to continue...";
+  size_t maxlen;
+  double n_lines_of_text;
+  int width;
+  int height;
+  int text_x0;
+  int text_x1;
+  int x1;
+  int text_y0;
+  int text_y1;
+  int y1;
+
+  HideMousePointer ();
+  maxlen = strlen (prompt3);
+  if (strlen (prompt1) > maxlen)
+    maxlen = strlen (prompt1);
+  if (prompt2 != NULL && strlen (prompt2) > maxlen)
+    maxlen = strlen (prompt2);
+  n_lines_of_text = (prompt2 == NULL ? 2.5 : 3.5);
+  width = 2 * BOX_BORDER + 2 * WIDE_HSPACING + maxlen * FONTW;
+  height = 2 * BOX_BORDER + 2 * WIDE_VSPACING + (int) (n_lines_of_text * FONTH);
+  if (x0 < 0)
+    x0 = (ScrMaxX - width) / 2;
+  if (y0 < 0)
+    y0 = (ScrMaxY - height) / 2;
+  text_x0 = x0 + BOX_BORDER + WIDE_HSPACING;
+  text_x1 = text_x0 + maxlen * FONTW - 1;
+  x1      = text_x1 + WIDE_HSPACING + BOX_BORDER;
+  text_y0 = y0 + BOX_BORDER + WIDE_VSPACING;
+  text_y1 = text_y0 + (int) (n_lines_of_text * FONTH) - 1;
+  y1      = text_y1 + WIDE_HSPACING + BOX_BORDER;
+  DrawScreenBox3D (x0, y0, x1, y1);
+  set_colour (WHITE);
+  DrawScreenText (text_x0, text_y0, prompt1);
+  if (prompt2 != NULL)
+    DrawScreenText (text_x0, text_y0 + FONTH, prompt2);
+  set_colour (WINTITLE);
+  DrawScreenText (text_x0, text_y1 - FONTH - 1, prompt3);
+  get_key_or_click ();
+  ShowMousePointer ();
+}
+
+
+/*
+ *	debmes - Display a message in a box only if in debug mode
+ *
+ *	Simple wrapper around Notify(). Don't try to make it display
+ *	more than 200 characters or you'll crash the program.
+ *	BUG: if result of formatting contains "%"'s, it will be
+ *	formatted again...
+ */
+void debmes (const char *fmt, ...)
+{
+  char buf[200];
+  va_list arglist;
+
+  if (Debug != 1)
+    return;
+  va_start (arglist, fmt);
+  y_vsnprintf (buf, sizeof buf, fmt, arglist);
+#ifdef Y_BGI
+  setviewport (0, 0, ScrMaxX, ScrMaxY, 1);
+#endif  /* FIXME! */
+  Notify (-1, -1, buf, NULL);
+}
+
+
+/*
+ *	DisplayMessage - clear the screen and display a message
+ */
+void DisplayMessage (int x0, int y0, const char *msg, ...)
+{
+  char prompt[120];
+  va_list args;
+
+  va_start (args, msg);
+  y_vsnprintf (prompt, sizeof prompt, msg, args);
+  int width = 2 * BOX_BORDER + 2 * WIDE_HSPACING + FONTW * strlen (prompt);
+  int height = 2 * BOX_BORDER + 2 * WIDE_VSPACING + FONTH;
+  if (x0 < 0)
+    x0 = (ScrMaxX - width) / 2;
+  if (y0 < 0)
+    y0 = (ScrMaxY - height) / 2;
+  HideMousePointer ();
+  DrawScreenBox3D (x0, y0, x0 + width - 1, y0 + height - 1);
+  push_colour (WINFG);
+  DrawScreenText (x0 + BOX_BORDER + WIDE_HSPACING,
+    y0 + BOX_BORDER + WIDE_VSPACING, prompt);
+  pop_colour ();
+  ShowMousePointer ();
+  XFlush (dpy);
+}
+
+
+/*
+ *	NotImplemented - make the user angry...
+ */
+void NotImplemented (void)
+{
+  Notify (-1, -1, "This function is not implemented... Yet!", NULL);
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/dialog.h	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,16 @@
+/*
+ *	dialog.h
+ *	Dialog boxes
+ *	AYM 1998-11-30
+ */
+
+
+bool Confirm (int, int, const char *, const char *);
+int Confirm2 (int x0, int y0, confirm_t *confirm_flag,
+   const char *prompt1, const char *prompt2);
+void Notify (int, int, const char *, const char *);
+void debmes (const char *fmt, ...);
+void DisplayMessage (int, int, const char *, ...);
+void NotImplemented (void);
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/disppic.cc	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,93 @@
+/*
+ *	disppic.cc
+ *	AYM 1998-08-30
+ */
+
+
+/*
+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"
+#ifdef Y_X11
+#include <X11/Xlib.h>
+#endif
+#include "gfx.h"
+#include "imgspect.h"
+#include "lists.h"
+#include "patchdir.h"
+#include "pic2img.h"
+#include "sticker.h"
+#include "wadres.h"
+
+
+/*
+ *	display_pic() -	load a picture and display it
+ *
+ *	A wrapper for LoadPicture() and Sticker.load()/draw().
+ */
+void display_pic (hookfunc_comm_t *c)
+{
+  int width  = c->x1 - c->x0 + 1;
+  int height = c->y1 - c->y0 + 1;
+  Lump_loc loc;
+
+  c->img.clear ();
+  c->img.set_opaque (false);
+  if (c->flags & HOOK_PATCH)
+    patch_dir.loc_by_name (c->name, loc);
+  else if ((c->flags & HOOK_SPRITE) && (c->flags & HOOK_ROOT))
+    wad_res.sprites.loc_by_root (c->name, loc);
+  else if ((c->flags & HOOK_SPRITE) && ! (c->flags & HOOK_ROOT))
+    wad_res.sprites.loc_by_name (c->name, loc);
+  if (! LoadPicture (c->img,
+    c->name,
+    loc,
+    0, // Not very clean, should use c->xofs but *WithFunc doesn't set it
+    0, // Not very clean, should use c->yofs but *WithFunc doesn't set it
+    &c->width,
+    &c->height))
+  {
+    c->disp_x0 = c->x0 + (width - c->width) / 2;
+    c->disp_y0 = c->y0 + (height - c->height) / 2;
+    c->disp_x1 = c->disp_x0 + c->width - 1;
+    c->disp_y1 = c->disp_y0 + c->height - 1;
+    c->flags |= HOOK_SIZE_VALID;
+    c->lump_loc = loc;
+    c->flags |= HOOK_LOC_VALID;
+    if (c->flags & HOOK_SPECTRAL)
+      spectrify_img (c->img);
+    Sticker sticker (c->img, true);  // Use opaque because it's faster
+    sticker.draw (drw, 't', c->disp_x0, c->disp_y0);
+    c->flags |= HOOK_DRAWN;
+  }
+  else
+  {
+    // Drew nothing (negative width and height)
+    c->disp_x0 = c->x0 + 1;
+    c->disp_y0 = c->y0 + 1;
+    c->disp_x1 = c->x0;
+    c->disp_y1 = c->y0;
+  }
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/disppic.h	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,17 @@
+/*
+ *	disppic.h
+ *	AYM 1998-08-30
+ */
+
+
+#ifndef YH_DISPPIC  /* DO NOT INSERT ANYTHING BEFORE THIS LINE */
+#define YH_DISPPIC
+
+
+#include "lists.h"
+
+
+void display_pic (hookfunc_comm_t *c);
+
+
+#endif  /* DO NOT ADD ANYTHING AFTER THIS LINE */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/drawmap.cc	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,825 @@
+/*
+ *	drawmap.cc
+ *	AYM 1998-09-06
+ */
+
+
+/*
+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 <math.h>
+#include <algorithm>
+#include <map>
+#include <vector>
+#ifdef Y_X11
+#  include <X11/Xlib.h>
+#endif
+#include "_edit.h"
+#include "disppic.h"  /* Sprites */
+#include "drawmap.h"
+#include "game.h"     /* Sprites */
+#include "gfx.h"
+#include "imgscale.h"
+#include "imgspect.h"
+#include "levels.h"
+#include "lists.h"
+#include "pic2img.h"
+#include "s_centre.h"
+#include "sticker.h"
+#include "things.h"
+#include "vectext.h"
+#include "wadres.h"
+
+
+static void draw_grid (edit_t *e);
+static void draw_vertices (edit_t *e);
+static void draw_linedefs (edit_t *e);
+static void draw_things_squares (edit_t *e);
+static void draw_things_sprites (edit_t *e);
+static void draw_obj_no (int x, int y, int obj_no, acolour_t c);
+
+
+/*
+ *	vertex_radius - apparent radius of a vertex, in pixels
+ *
+ *	Try this in Gnuplot :
+ *
+ *	  plot [0:10] x                                          
+ *	  replot log(x+1.46)/log(1.5)-log(2.46)/log(1.5)+1
+ */
+int vertex_radius (double scale)
+{
+#if 0
+  static double last_scale = 0;
+  static int    last_result = 0;
+
+  if (scale == last_scale)
+    return last_result;
+
+  const int    VERTEX_PIXELS  = 5;
+
+  // The scale past which we switch from linear to logarithmic.
+  const double crossover      = 0.1;
+
+  // The base of the log. The higher, the stronger the effect.
+  const double base           = 1.4;
+
+  /* The point at which the derivative of log{base}(x) is 1.
+     This is where we want the crossover to occur. */
+  const double knee_x         = 1 / log (base);
+  const double knee_y         = log (knee_x) / log (base);
+
+  double factor;
+  if (scale <= crossover)
+    factor = scale;
+  else
+    factor = crossover + log (scale -crossover + knee_x) / log (base) - knee_y;
+  last_result = (int) (VERTEX_PIXELS * factor + 0.5);
+  return last_result;
+#else
+  const int VERTEX_PIXELS = 6;
+  return (int) (VERTEX_PIXELS * (0.2 + scale / 2));
+#endif
+}
+
+
+/*
+  draw the actual game map
+*/
+
+void draw_map (edit_t *e) /* SWAP! */
+{
+  int mapx0 = MAPX (0);
+  int mapx9 = MAPX (ScrMaxX);
+  int mapy0 = MAPY (ScrMaxY);
+  int mapy9 = MAPY (0);
+  int n;
+
+
+  // Draw the grid first since it's in the background
+  draw_grid (e);
+
+  if (e->global)
+  {
+    draw_linedefs (e);
+    if (e->show_things_sprites)
+      draw_things_sprites (e);
+    else
+      draw_things_squares (e);
+    draw_vertices (e);
+  }
+  else
+  {
+    if (e->obj_type != OBJ_THINGS)
+      draw_things_squares (e);
+    draw_linedefs (e);
+    if (e->obj_type == OBJ_VERTICES)
+      draw_vertices (e);
+    if (e->obj_type == OBJ_THINGS)
+    {
+      if (e->show_things_sprites)
+	draw_things_sprites (e);
+      else
+	draw_things_squares (e);
+    }
+  }
+
+
+  // Draw the things numbers
+  if (e->obj_type == OBJ_THINGS && e->show_object_numbers)
+  {
+    for (n = 0; n < NumThings; n++)
+    {
+      int mapx = Things[n].xpos;
+      int mapy = Things[n].ypos;
+      if (mapx < mapx0 || mapx > mapx9 || mapy < mapy0 || mapy > mapy9)
+	continue;
+      draw_obj_no (SCREENX (mapx) + FONTW, SCREENY (mapy) + 2, n, THING_NO);
+    }
+  }
+
+  // Draw the sector numbers
+  if (e->obj_type == OBJ_SECTORS && e->show_object_numbers)
+  {
+    int xoffset = - FONTW / 2;
+
+    for (n = 0; n < NumSectors; n++)
+    {
+      int mapx;
+      int mapy;
+      centre_of_sector (n, &mapx, &mapy);
+      if (mapx >= mapx0 && mapx <= mapx9 && mapy >= mapy0 && mapy <= mapy9)
+	draw_obj_no (SCREENX (mapx) + xoffset, SCREENY (mapy) - FONTH / 2, n,
+	  SECTOR_NO);
+      if (n == 10 || n == 100 || n == 1000 || n == 10000)
+	xoffset -= FONTW / 2;
+    }
+  }
+}
+
+
+/*
+ *	draw_grid - draw the grid in the background of the edit window
+ */
+static void draw_grid (edit_t *e)
+{
+  if (! e->grid_shown)
+    return;
+  
+  int mapx0   = MAPX (0);
+  int mapx1   = MAPX (ScrMaxX);
+  int mapy0   = MAPY (ScrMaxY);
+  int mapy1   = MAPY (0);
+
+  int grid_step_1 = e->grid_step;	// Map units between dots
+  int grid_step_2 = 4 * grid_step_1;	// Map units between dim lines
+  int grid_step_3 = 4 * grid_step_2;	// Map units between bright lines
+  int grid_step_4 = 4 * grid_step_3;	// Map units between brighter lines
+
+  {
+    set_colour (GRID2V);
+    int mapx0_2 = (mapx0 / grid_step_2) * grid_step_2;
+    if (mapx0_2 < mapx0)
+      mapx0_2 += grid_step_2;
+    for (int i = mapx0_2; i <= mapx1; i += grid_step_2)
+      if (i % grid_step_3 != 0)
+	DrawMapLine (i, mapy0, i, mapy1);
+  }
+
+  {
+    set_colour (GRID2H);
+    int mapy0_2 = (mapy0 / grid_step_2) * grid_step_2;
+    if (mapy0_2 < mapy0)
+      mapy0_2 += grid_step_2;
+    for (int j = mapy0_2; j <=  mapy1; j += grid_step_2)
+      if (j % grid_step_3 != 0)
+	DrawMapLine (mapx0, j, mapx1, j);
+  }
+
+  {
+    set_colour (GRID3V);
+    int mapx0_3 = (mapx0 / grid_step_3) * grid_step_3;
+    if (mapx0_3 < mapx0)
+      mapx0_3 += grid_step_3;
+    for (int i = mapx0_3; i <= mapx1; i += grid_step_3)
+      if (i % grid_step_4 != 0)
+	DrawMapLine (i, mapy0, i, mapy1);
+  }
+
+  {
+    set_colour (GRID3H);
+    int mapy0_3 = (mapy0 / grid_step_3) * grid_step_3;
+    if (mapy0_3 < mapy0)
+      mapy0_3 += grid_step_3;
+    for (int j = mapy0_3; j <=  mapy1; j += grid_step_3)
+      if (j % grid_step_4 != 0)
+	DrawMapLine (mapx0, j, mapx1, j);
+  }
+
+  {
+    set_colour (GRID4V);
+    int mapx0_4 = (mapx0 / grid_step_4) * grid_step_4;
+    if (mapx0_4 < mapx0)
+      mapx0_4 += grid_step_4;
+    //printf ("MAPX(0): %d  mapx0_4: %d\n", MAPX(0), mapx0_4);  // DEBUG
+    for (int i = mapx0_4; i <= mapx1; i += grid_step_4)
+      DrawMapLine (i, mapy0, i, mapy1);
+  }
+
+  {
+    set_colour (GRID4H);
+    int mapy0_4 = (mapy0 / grid_step_4) * grid_step_4;
+    if (mapy0_4 < mapy0)
+      mapy0_4 += grid_step_4;
+    for (int j = mapy0_4; j <=  mapy1; j += grid_step_4)
+      DrawMapLine (mapx0, j, mapx1, j);
+  }
+
+  {
+    int mapx0_1 = (mapx0 / grid_step_1) * grid_step_1;
+    if (mapx0_1 < mapx0)
+      mapx0_1 += grid_step_1;
+    int mapy0_1 = (mapy0 / grid_step_1) * grid_step_1;
+    if (mapy0_1 < mapy0)
+      mapy0_1 += grid_step_1;
+
+#ifdef Y_X11
+    // Optimisation for X: draw several points in one go
+    int npoints = (mapx1 - mapx0_1) / grid_step_1 + 1;
+    XPoint *points = (XPoint *) malloc (npoints * sizeof *points);
+    points[0].x = SCREENX (mapx0_1);
+    int n = 1;
+    int last_i = points[0].x;
+    for (int i = mapx0_1 + grid_step_1; i <= mapx1; i += grid_step_1)
+    {
+      if (n >= npoints)
+	nf_bug ("%d >= %d", n, npoints);
+      points[n].x = SCREENX (i) - last_i;
+      points[n].y = 0;
+      n++;
+      last_i = SCREENX (i);
+    }
+    npoints = n;
+    set_colour (GRID1);
+    for (int j = mapy0_1; j <= mapy1; j += grid_step_1)
+    {
+      points[0].y = SCREENY (j);
+      XDrawPoints (dpy, drw, gc, points, npoints, CoordModePrevious);
+    }
+    free (points);
+#else
+    // Generic code. Untested.
+    int npoints = (mapx1 - mapx0_1) / grid_step_1 + 1;
+    int dispx[npoints];
+    for (int n = 0; n < npoints; n++)
+      dispx[n] = SCREENX (mapx0_1 + n * grid_step_1);
+    for (int j = mapy0_1; j <= mapy1; j += grid_step_1)
+    {
+      int dispy = SCREENY (j);
+      for (int n = 0; n < npoints; n++)
+      {
+	draw_point (dispx[n], dispy);
+      }
+    }
+#endif
+  }
+}
+
+
+/*
+ *	draw_vertices - draw the vertices, and possibly their numbers
+ */
+static void draw_vertices (edit_t *e)
+{
+  int mapx0 = MAPX (0);
+  int mapx9 = MAPX (ScrMaxX);
+  int mapy0 = MAPY (ScrMaxY);
+  int mapy9 = MAPY (0);
+  const int r = vertex_radius (Scale);
+
+  push_colour (LIGHTGREEN);
+  for (int n = 0; n < NumVertices; n++)
+  {
+    int mapx = Vertices[n].x;
+    int mapy = Vertices[n].y;
+    if (mapx >= mapx0 && mapx <= mapx9 && mapy >= mapy0 && mapy <= mapy9)
+    {
+      register int scrx = SCREENX (mapx);
+      register int scry = SCREENY (mapy);
+      DrawScreenLine (scrx - r, scry - r, scrx + r, scry + r);
+      DrawScreenLine (scrx + r, scry - r, scrx - r, scry + r);
+    }
+  }
+  if (e->show_object_numbers)
+  {
+    for (int n = 0; n < NumVertices; n++)
+    {
+      int mapx = Vertices[n].x;
+      int mapy = Vertices[n].y;
+      if (mapx >= mapx0 && mapx <= mapx9 && mapy >= mapy0 && mapy <= mapy9)
+      {
+	int x = (int) (SCREENX (mapx) + 2 * r);
+	int y = SCREENY (mapy) + 2;
+	draw_obj_no (x, y, n, VERTEX_NO);
+      }
+    }
+  }
+  pop_colour ();
+}
+
+
+/*
+ *	draw_linedefs - draw the linedefs
+ */
+static void draw_linedefs (edit_t *e)
+{
+  int mapx0 = MAPX (0);
+  int mapx9 = MAPX (ScrMaxX);
+  int mapy0 = MAPY (ScrMaxY);
+  int mapy9 = MAPY (0);
+
+  switch (e->obj_type)
+  {
+    case OBJ_THINGS:
+    {
+      int current_colour = INT_MIN;  /* Some impossible colour no. */
+      int new_colour;
+      
+      ObjectsNeeded (OBJ_LINEDEFS, OBJ_VERTICES, 0);
+      for (int n = 0; n < NumLineDefs; n++)
+      {
+	register int x1 = Vertices[LineDefs[n].start].x;
+	register int x2 = Vertices[LineDefs[n].end  ].x;
+	register int y1 = Vertices[LineDefs[n].start].y;
+	register int y2 = Vertices[LineDefs[n].end  ].y;
+	if (x1 < mapx0 && x2 < mapx0
+	 || x1 > mapx9 && x2 > mapx9
+	 || y1 < mapy0 && y2 < mapy0
+	 || y1 > mapy9 && y2 > mapy9)
+	  continue;
+	if (LineDefs[n].flags & 1)
+	  new_colour = WHITE;
+	else
+	  new_colour = LIGHTGREY;
+	if (new_colour != current_colour)
+	  set_colour (current_colour = new_colour);
+	DrawMapLine (x1, y1, x2, y2);
+      }
+      break;
+    }
+
+    case OBJ_VERTICES:
+      ObjectsNeeded (OBJ_LINEDEFS, OBJ_VERTICES, 0);
+      set_colour (LIGHTGREY);
+      for (int n = 0; n < NumLineDefs; n++)
+      {
+	register int x1 = Vertices[LineDefs[n].start].x;
+	register int x2 = Vertices[LineDefs[n].end  ].x;
+	register int y1 = Vertices[LineDefs[n].start].y;
+	register int y2 = Vertices[LineDefs[n].end  ].y;
+	if (x1 < mapx0 && x2 < mapx0
+	 || x1 > mapx9 && x2 > mapx9
+	 || y1 < mapy0 && y2 < mapy0
+	 || y1 > mapy9 && y2 > mapy9)
+	  continue;
+	DrawMapVector (x1, y1, x2, y2);
+      }
+      break;
+
+    case OBJ_LINEDEFS:
+    {
+      int current_colour = INT_MIN;  /* Some impossible colour no. */
+      int new_colour;
+
+      ObjectsNeeded (OBJ_LINEDEFS, OBJ_VERTICES, 0);
+      for (int n = 0; n < NumLineDefs; n++)
+      {
+	register int x1 = Vertices[LineDefs[n].start].x;
+	register int x2 = Vertices[LineDefs[n].end  ].x;
+	register int y1 = Vertices[LineDefs[n].start].y;
+	register int y2 = Vertices[LineDefs[n].end  ].y;
+	if (x1 < mapx0 && x2 < mapx0
+	 || x1 > mapx9 && x2 > mapx9
+	 || y1 < mapy0 && y2 < mapy0
+	 || y1 > mapy9 && y2 > mapy9)
+	  continue;
+	if (LineDefs[n].type != 0)  /* AYM 19980207: was "> 0" */
+	{
+	  if (LineDefs[n].tag != 0)  /* AYM 19980207: was "> 0" */
+	    new_colour = LIGHTMAGENTA;
+	  else
+	    new_colour = LIGHTGREEN;
+	}
+	else if (LineDefs[n].flags & 1)
+	  new_colour = WHITE;
+	else
+	  new_colour = LIGHTGREY;
+
+	// Signal errors by drawing the linedef in red. Needs work.
+	// Tag on a typeless linedef
+	if (LineDefs[n].type == 0 && LineDefs[n].tag != 0)
+	  new_colour = LIGHTRED;
+	// No first sidedef
+	if (! is_sidedef (LineDefs[n].sidedef1))
+	  new_colour = LIGHTRED;
+	// Bad second sidedef
+	if (! is_sidedef (LineDefs[n].sidedef2) && LineDefs[n].sidedef2 != -1)
+	  new_colour = LIGHTRED;
+
+	if (new_colour != current_colour)
+	  set_colour (current_colour = new_colour);
+	DrawMapLine (x1, y1, x2, y2);
+
+	if (e->show_object_numbers)
+	{
+	  int scnx0       = SCREENX (x1);
+	  int scnx1       = SCREENX (x2);
+	  int scny0       = SCREENY (y1);
+	  int scny1       = SCREENY (y2);
+	  int label_width = ((int) log10 (n) + 1) * FONTW;
+	  if (abs (scnx1 - scnx0) > label_width + 4
+	   || abs (scny1 - scny0) > label_width + 4)
+	  {
+	    int scnx = (scnx0 + scnx1) / 2 - label_width / 2;
+	    int scny = (scny0 + scny1) / 2 - FONTH / 2;
+	    draw_obj_no (scnx, scny, n, LINEDEF_NO);
+	  }
+	}
+      }
+      break;
+    }
+
+    case OBJ_SECTORS:
+    {
+      int current_colour = INT_MIN;  /* Some impossible colour no. */
+      int new_colour;
+
+      for (int n = 0; n < NumLineDefs; n++)
+      {
+	register int x1 = Vertices[LineDefs[n].start].x;
+	register int x2 = Vertices[LineDefs[n].end  ].x;
+	register int y1 = Vertices[LineDefs[n].start].y;
+	register int y2 = Vertices[LineDefs[n].end  ].y;
+	if (x1 < mapx0 && x2 < mapx0
+	 || x1 > mapx9 && x2 > mapx9
+	 || y1 < mapy0 && y2 < mapy0
+	 || y1 > mapy9 && y2 > mapy9)
+	  continue;
+	int sd1 = OBJ_NO_NONE;
+	int sd2 = OBJ_NO_NONE;
+	int s1  = OBJ_NO_NONE;
+	int s2  = OBJ_NO_NONE;
+	// FIXME should flag negative sidedef numbers as errors
+	// FIXME should flag unused tag as errors
+	if ((sd1 = LineDefs[n].sidedef1) < 0 || sd1 >= NumSideDefs
+	  || (s1 = SideDefs[sd1].sector) < 0 || s1 >= NumSectors
+	  || (sd2 = LineDefs[n].sidedef2) >= NumSideDefs
+	  || sd2 >= 0 && ((s2 = SideDefs[sd2].sector) < 0
+			|| s2 >= NumSectors))
+	{
+	  new_colour = LIGHTRED;
+	}
+	else
+	{
+	  bool have_tag  = false;
+	  bool have_type = false;
+	  if (Sectors[s1].tag != 0)
+	    have_tag = true;
+	  if (Sectors[s1].special != 0)
+	    have_type = true;
+	  if (sd2 >= 0)
+	  {
+	    if (Sectors[s2].tag != 0)
+	      have_tag = true;
+	    if (Sectors[s2].special != 0)
+	      have_type = true;
+	  }
+	  if (have_tag && have_type)
+	    new_colour = SECTOR_TAGTYPE;
+	  else if (have_tag)
+	    new_colour = SECTOR_TAG;
+	  else if (have_type)
+	    new_colour = SECTOR_TYPE;
+	  else if (LineDefs[n].flags & 1)
+	    new_colour = WHITE;
+	  else
+	    new_colour = LIGHTGREY;
+	}
+	if (new_colour != current_colour)
+	  set_colour (current_colour = new_colour);
+	DrawMapLine (x1, y1, x2, y2);
+      }
+      break;
+    }
+  }
+}
+
+
+/*
+ *	draw_things_squares - the obvious
+ */
+static void draw_things_squares (edit_t *e)
+{
+  // The radius of the largest thing.
+  int max_radius = get_max_thing_radius ();
+
+  /* A thing is guaranteed to be totally off-screen
+     if its centre is more than <max_radius> units
+     beyond the edge of the screen. */
+  int mapx0      = MAPX (0)       - max_radius;
+  int mapx9      = MAPX (ScrMaxX) + max_radius;
+  int mapy0      = MAPY (ScrMaxY) - max_radius;
+  int mapy9      = MAPY (0)       + max_radius;
+
+  push_colour (THING_REM);
+  for (int n = 0; n < NumThings; n++)
+  {
+    int mapx = Things[n].xpos;
+    int mapy = Things[n].ypos;
+    int corner_x;
+    int corner_y;
+    if (mapx < mapx0 || mapx > mapx9 || mapy < mapy0 || mapy > mapy9)
+      continue;
+    int m = get_thing_radius (Things[n].type);
+    if (e->obj_type == OBJ_THINGS)
+      set_colour (get_thing_colour (Things[n].type));
+#ifdef ROUND_THINGS
+    DrawMapLine (mapx - m, mapy,     mapx + m, mapy    );
+    DrawMapLine (mapx,     mapy - m, mapx,     mapy + m);
+    DrawMapCircle (mapx, mapy, m);
+#else
+    DrawMapLine (mapx - m, mapy - m, mapx + m, mapy - m);
+    DrawMapLine (mapx + m, mapy - m, mapx + m, mapy + m);
+    DrawMapLine (mapx + m, mapy + m, mapx - m, mapy + m);
+    DrawMapLine (mapx - m, mapy + m, mapx - m, mapy - m);
+#endif
+    {
+      size_t direction = angle_to_direction (Things[n].angle);
+      static const short xsign[] = {  1,  1,  0, -1, -1, -1,  0,  1,  0 };
+      static const short ysign[] = {  0,  1,  1,  1,  0, -1, -1, -1,  0 };
+      corner_x = m * xsign[direction];
+      corner_y = m * ysign[direction];
+    }
+    DrawMapLine (mapx, mapy, mapx + corner_x, mapy + corner_y);
+  }
+  pop_colour ();
+}
+
+
+/* Drawing the things sprites is done here.
+
+   To avoid having large sprites obscure small ones, we display
+   the large sprites first and the small ones last. To do that,
+   we maintain a list of all things in the level, sorted in
+   descending number of opaque pixels in the sprite. Actually,
+   we approximate that by the size of the lump. Usually, the
+   size of the lump is roughly monotonic w.r.t. the number of
+   opaque pixels. And it's much simpler and faster than counting
+   the pixels.
+
+   That list serves a second purpose : optimization. Because of
+   the way it's sorted, two things that have the same graphic
+   representation are always contiguous in the list. That
+   property allows us to save quite a few calls to
+   LoadPicture(), scale_img(), spectrify_img() and
+   Sticker::load(). Given that those are very expensive
+   operations and that the average level contains many
+   repetitions of certain things (E.G. former humans), the
+   benefit is considerable. On certain semi-pathological levels
+   like Robin Holden's court30.wad, it makes display several
+   times faster.
+
+   We approximate "two things have the same graphic
+   represention" by "two things have the same type". Strictly
+   speaking, it's not the same thing. Two distinct thing types
+   could very well have the same graphic representation. In fact
+   it does happen (cf. things 49 and 63). However, since the
+   alternative is to sort based on the quintuplet (wad, lump
+   offset, flags, dye), we're better off this way. */
+
+
+class Thing_npixels
+{
+  public :
+    Thing_npixels (i16 thing_no, unsigned long npixels, wad_ttype_t type)
+      : thing_no (thing_no), npixels (npixels), type (type) { }
+    bool operator< (const Thing_npixels& other) const
+      { if (this->npixels > other.npixels  // Decreasing npixels major
+	    || this->npixels == other.npixels  // Increasing type minor
+	       && this->type < other.type)
+	  return true;
+	return false;
+      }
+    i16 thing_no;
+    unsigned long npixels;
+    wad_ttype_t type;
+};
+
+
+class Thing_list_by_size
+{
+  public :
+    Thing_list_by_size () { }
+    ~Thing_list_by_size () { }
+    const Thing_npixels& operator[] (int n) { return a[n]; }
+    void refresh ()
+    {
+      a.clear ();
+      a.reserve (NumThings);
+      for (int n = 0; n < NumThings; n++)
+      {
+	Lump_loc loc;
+	const char *sprite_root = get_thing_sprite (Things[n].type);
+	if (sprite_root != NULL)
+	  wad_res.sprites.loc_by_root (sprite_root, loc);
+	else
+	  loc.len = 0;
+	a.push_back (Thing_npixels ((i16) n, loc.len, Things[n].type));
+      }
+      sort (a.begin (), a.end ());
+    }
+  private :
+    std::vector <Thing_npixels> a;
+};
+
+
+static Thing_list_by_size list;
+//static unsigned long things_angles_prev;  // Unused for now
+static unsigned long things_types_prev;
+
+
+/* This map is used to cache widths and heights. We need them
+   to skip off-screen sprites. */
+
+struct sprite_dim_t
+{
+  sprite_dim_t () { }
+  sprite_dim_t (int width, int height) : width (width), height (height) { }
+  unsigned short width;
+  unsigned short height;
+};
+
+typedef std::map <i16, sprite_dim_t> dim_map_t;
+static dim_map_t dim_map;  // FIXME there should be one for each game
+
+
+/*
+ *	draw_things_sprites - the obvious
+ */
+static void draw_things_sprites (edit_t *e)
+{
+#ifdef NO_RENDER
+  static
+#endif
+  Sticker      sticker;
+  wad_ttype_t last_type = -1;  // Type of last thing displayed
+  dim_map_t::iterator dim = dim_map.end ();
+  bool set_dim = true;  // Init to avoid warning
+  const unsigned short max_width  = 1000;
+  const unsigned short max_height = 1000;
+  int mapx0 = 0;
+  int mapx9 = 0;
+  int mapy0 = 0;
+  int mapy9 = 0;
+
+  if (things_types_prev != things_types)
+  {
+    list.refresh ();
+    things_types_prev = things_types;
+  }
+
+#ifdef NO_RENDER
+  static double last_scale = 0;
+  if (last_scale != Scale)
+  {
+    Lump_loc loc;
+    wad_res.sprites.loc_by_root ("PLAY", loc);
+    Img img;
+    LoadPicture (img, "PLAYA0", loc, 0, 0);
+    Img img_scaled;
+    scale_img (img, Scale * sprite_scale / 100, img_scaled);
+    sprite.load (img_scaled, false);
+    last_scale = Scale;
+  }
+#endif
+  push_colour (CYAN);
+  for (int n = 0; n < NumThings; n++)
+  {
+    const Thing_npixels& t = list[n];
+
+    // Skip off-screen things
+    if (t.type != last_type)
+    {
+      dim = dim_map.find (t.type);
+      if (dim == dim_map.end ())
+      {
+	set_dim = true;
+	mapx0 = MAPX (0)       - max_width / 2;
+	mapx9 = MAPX (ScrMaxX) + max_width / 2;
+	mapy0 = MAPY (ScrMaxY) - max_height / 2;
+	mapy9 = MAPY (0)       + max_height / 2;
+      }
+      else
+      {
+	mapx0 = MAPX (0)       - dim->second.width / 2;
+	mapx9 = MAPX (ScrMaxX) + dim->second.width / 2;
+	mapy0 = MAPY (ScrMaxY) - dim->second.height / 2;
+	mapy9 = MAPY (0)       + dim->second.height / 2;
+      }
+    }
+    int mapx = Things[t.thing_no].xpos;
+    int mapy = Things[t.thing_no].ypos;
+    if (mapx < mapx0 || mapx > mapx9 || mapy < mapy0 || mapy > mapy9)
+      continue;
+
+#ifndef NO_RENDER
+    // If not the same as the last thing displayed, rasterize it
+    if (t.type != last_type)
+    {
+      last_type = t.type;
+
+      const char *sprite_root = get_thing_sprite (t.type);
+      if (sprite_root != NULL)
+      {
+	Lump_loc loc;
+	wad_res.sprites.loc_by_root (sprite_root, loc);
+	Img img_raw, img_scaled;
+	if (LoadPicture (img_raw, sprite_root, loc, 0, 0))
+	{
+	  sticker.clear ();  // We'll display the thing type instead
+	}
+	else
+	{
+	  if (set_dim)
+	  {
+	    dim_map[t.type] = sprite_dim_t (img_raw.width(), img_raw.height());
+	    set_dim = false;
+	  }
+	  scale_img (img_raw, Scale * sprite_scale / 100, img_scaled);
+	  if (get_thing_flags (t.type) & THINGDEF_SPECTRAL)
+	     spectrify_img (img_scaled);
+	  sticker.load (img_scaled, false);
+	}
+      }
+      else
+	sticker.clear ();  // We'll display the thing type instead
+    }
+#endif
+    
+    // Display it
+    if (sticker.is_clear ())
+      draw_vint (t.type, SCREENX (mapx), SCREENY (mapy), Scale);
+    else
+      sticker.draw (drw, 'c', SCREENX (mapx), SCREENY (mapy));
+  }
+  pop_colour ();
+}
+
+
+/*
+ *	draw_obj_no - draw a number at screen coordinates (x, y)
+ *
+ *	FIXME too slow.
+ */
+static void draw_obj_no (int x, int y, int obj_no, acolour_t c)
+{
+  push_colour (BLACK);
+#if 1
+  DrawScreenText (x - 2, y,     "%d", obj_no);
+  DrawScreenText (x - 1, y,     "%d", obj_no);
+  DrawScreenText (x + 1, y,     "%d", obj_no);
+  DrawScreenText (x + 2, y,     "%d", obj_no);
+  DrawScreenText (x,     y + 1, "%d", obj_no);
+  DrawScreenText (x,     y - 1, "%d", obj_no);
+#else
+  DrawScreenText (x + 1, y + 1, "%d", obj_no);
+  DrawScreenText (x + 1, y - 1, "%d", obj_no);
+  DrawScreenText (x - 1, y + 1, "%d", obj_no);
+  DrawScreenText (x - 1, y - 1, "%d", obj_no);
+#endif
+  set_colour (c);
+  DrawScreenText (x,     y,     "%d", obj_no);
+  pop_colour ();
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/drawmap.h	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,19 @@
+/*
+ *	drawmap.h
+ *	AYM 1998-09-06
+ */
+
+
+#ifndef YH_DRAWMAP
+#define YH_DRAWMAP
+
+#include "_edit.h"
+
+
+int vertex_radius (double scale);
+
+void draw_map (edit_t *e);
+void draw_infobar (const edit_t *e);
+
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/edisplay.cc	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,217 @@
+/*
+ *	edisplay.cc
+ *	The edisplay_c (edit window display) class
+ *	AYM 1998-09-16
+ */
+
+
+/*
+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.
+*/
+
+
+/*
+The edisplay_c class is the interface between the edit_c class
+(the edit window at an abstract level) and the various edwidget_c
+descended classes (the widgets used to represent the edit window
+on the display). Its role is to allow the edit_c class to feel
+the bliss that comes from ignoring the gory details of handling
+the display in a somewhat asynchronous and optimized fashion.
+
+The other role of the edisplay_c class is to act as a kind of
+rudimentary geometry manager for the widgets.
+
+About undrawing :
+Some widgets are able to undraw themselves. Some are not. If we
+want to undraw them, then we should clear the window and redraw
+everything from scratch. That's what the method need_to_clear()
+is for; if the widget should be undrawn but can't undraw itself,
+need_to_clear() returns true.
+
+For the time being, the set of widgets is hard coded into the
+edisplay_c class. But this needs not be. In the future, all this
+should be replaced by a loop through a list of widgets.
+*/
+
+
+#include "yadex.h"
+#include "_edit.h"
+#include "drawmap.h"
+#include "edisplay.h"
+#include "editobj.h"
+#include "gfx.h"
+#include "highlt.h"
+#include "infobar.h"
+#include "levels.h"	// Level
+#include "menu.h"
+#include "menubar.h"
+#include "modpopup.h"
+#include "objects.h"
+#include "objinfo.h"
+#include "selbox.h"
+#include "spot.h"
+#include "wadfile.h"
+
+
+edisplay_c::edisplay_c (edit_t *e)
+{
+  this->e = e;
+  pointer_scnx = 0;
+  pointer_scny = 0;
+  refresh_needed = 1;
+  highlight = new highlight_c;
+  objinfo   = new objinfo_c;
+  infobar   = new infobar_c;
+}
+
+
+edisplay_c::~edisplay_c ()
+{
+  delete highlight;
+  delete objinfo;
+}
+
+
+// FIXME this should not be a separate method
+void edisplay_c::highlight_object (Objid& obj)
+{
+  highlight->set (obj);
+  objinfo->set (obj.type, obj.num);
+}
+
+
+// FIXME this should not be a separate method
+void edisplay_c::forget_highlight ()
+{
+  highlight->unset ();
+  /* I don't unset objinfo because, as it can't undraw
+     itself, it would lead to redrawing everything from
+     scratch everytime an object passes out of focus. */
+  //objinfo->unset ();
+}
+
+
+void edisplay_c::need_refresh ()
+{
+  refresh_needed = 1;
+}
+
+
+void edisplay_c::refresh ()
+{
+  int redraw_from_scratch;
+
+  // The poor hacker's geometry manager (FIXME: this needs work!)
+  infobar->set_x1 (ScrMaxX);
+  infobar->set_y1 (ScrMaxY);
+  infobar->set_x0 (0);
+  infobar->set_y0 (ScrMaxY - (infobar->req_height () - 1));
+  objinfo->set_y1 (e->infobar_shown ? infobar->get_y0 () - 1 : ScrMaxY);
+
+  /* Extract the interesting data from the edit_c object
+     and feed it to the widgets. */
+  infobar->set_visible          (e->infobar_shown);
+  infobar->set_file_name        (Level
+				   ? Level->wadfile->pathname ()
+				   : 0);
+  infobar->set_level_name       (Level
+				   ? (const char *) Level->dir.name
+				   : 0);
+  infobar->set_obj_type         (e->obj_type);
+  infobar->set_changes          (MadeMapChanges ? 2 : (MadeChanges ? 1 : 0));
+  infobar->set_grid_snap        (e->grid_snap);
+  infobar->set_grid_step_locked (e->grid_step_locked);
+  infobar->set_scale            (Scale);
+  infobar->set_grid_step        (e->grid_step);
+  if (e->pointer_in_window)
+    infobar->set_pointer (e->pointer_x, e->pointer_y);
+  else
+    infobar->unset_pointer ();
+
+
+  redraw_from_scratch =
+    refresh_needed
+    || e->selbox->need_to_clear   ()
+    || e->spot->need_to_clear     ()
+    || highlight->need_to_clear   ()
+    || objinfo->need_to_clear     ()
+    || infobar->need_to_clear     ()
+    || e->menubar->need_to_clear  ()
+    || e->modpopup->need_to_clear ();
+   
+  /* If we can update the display in an incremental fashion
+     (not from scratch), do it by telling all widgets, from
+     the top to the bottom, to undraw themselves if necessary. */
+  if (! redraw_from_scratch)
+  {
+    e->modpopup->undraw ();
+    e->menubar->undraw  ();
+    infobar->undraw     ();
+    objinfo->undraw     ();
+    highlight->undraw   ();
+    e->spot->undraw     ();
+    e->selbox->undraw   ();
+  }
+
+  /* If a complete refresh is required, call the clear()
+     method for all widgets to make them aware that they're
+     not visible anymore. */
+  else
+  {
+    e->selbox->clear   ();
+    e->spot->clear     ();
+    highlight->clear   ();
+    objinfo->clear     ();
+    infobar->clear     ();
+    e->menubar->clear  ();
+    e->modpopup->clear ();
+
+    // A piece of ad-hockery
+    objinfo->unset ();
+
+    // As we said, "from scratch".
+    ClearScreen ();
+    draw_map (e);     // FIXME should be widgetized
+    // draw_menubar ();  // FIXME should be widgetized
+    HighlightSelection (e->obj_type, e->Selected); // FIXME should be widgetized
+    refresh_needed = 0;
+  }
+
+  /* Tell all widgets from to bottom to the top
+     to draw themselves if necessary. */
+  e->selbox->draw   ();
+  e->spot->draw     ();
+  highlight->draw   ();
+  if (e->objinfo_shown)
+    objinfo->draw     ();
+  infobar->draw     ();
+  e->menubar->draw  ();
+  e->modpopup->draw ();
+
+  // Redraw the pointer if necessary.
+  if (refresh_needed && (FakeCursor || e->rulers_shown))
+    DrawPointer (e->rulers_shown);  // FIXME should be widgetized
+
+  // Refresh the physical display
+  update_display ();
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/edisplay.h	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,35 @@
+/*
+ *	edisplay.h
+ *	AYM 1998-09-16
+ */
+
+
+class highlight_c;
+class infobar_c;
+class objinfo_c;
+
+
+class edisplay_c
+   {
+   public :
+      edisplay_c (edit_t *e);
+      ~edisplay_c ();
+      void refresh ();
+      void need_refresh ();
+      void highlight_object (Objid& obj);
+      void forget_highlight ();
+
+   private :
+      edit_t *e;		/* Parent editing window */
+      int requested_highlight;	/* No. of object that should be highlighted */
+      int actual_highlight;	/* No. of object that really is highlighted */
+      int pointer_scnx;		/* Physical position of the pointer */
+      int pointer_scny;
+      int refresh_needed;	/* If true, the display needs to be refreshed */
+      highlight_c *highlight;
+      objinfo_c *objinfo;
+      infobar_c *infobar;
+   };
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/editgrid.cc	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,46 @@
+/*
+ *	editgrid.cc
+ *	AYM 1998-11-09
+ */
+
+
+/*
+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 "_edit.h"
+#include "editgrid.h"
+
+
+void edit_grid_adapt (edit_t *e)
+{
+  if (! e->grid_step_locked)
+    for (e->grid_step = e->grid_step_max;
+	 e->grid_step * Scale / 2 >= grid_pixels_min;
+	 e->grid_step /= 2)
+      ;
+}
+
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/editgrid.h	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,74 @@
+/*
+ *	editgrid.h
+ *	AYM 1998-11-09
+ */
+
+
+/*
+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.
+*/
+
+
+void edit_grid_adapt (edit_t *e);
+
+
+/*
+ *	edit_mapx_snapped
+ *	Return <mapx> snapped to grid
+ *	(or unchanged is snap_to_grid is off)
+ */
+inline int edit_mapx_snapped (const edit_t *e, int mapx)
+{
+if (! e->grid_snap || e->grid_step == 0)
+   return mapx;
+if (mapx >= 0)
+   return e->grid_step * ((mapx + e->grid_step / 2) / e->grid_step);
+else
+   return e->grid_step * ((mapx - e->grid_step / 2) / e->grid_step);
+}
+
+
+/*
+ *	edit_mapy_snapped
+ *	Return <mapy> snapped to grid
+ *	(or unchanged is snap_to_grid is off)
+ */
+inline int edit_mapy_snapped (const edit_t *e, int mapy)
+{
+if (! e->grid_snap || e->grid_step == 0)
+   return mapy;
+if (mapy >= 0)
+   return e->grid_step * ((mapy + e->grid_step / 2) / e->grid_step);
+else
+   return e->grid_step * ((mapy - e->grid_step / 2) / e->grid_step);
+}
+
+
+/* The old method for snapping to grid.
+   Required that grid_step be a power of 2. */
+#if 0
+(MAPX (is.x) + e.grid_step / 2) & ~(e.grid_step - 1),
+(MAPY (is.y) + e.grid_step / 2) & ~(e.grid_step - 1));
+MoveObjectsToCoords (e.obj_type, 0,
+e.pointer_x, e.pointer_y, e.grid_snap ? e.grid_step : 0);
+#endif
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/editlev.cc	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,285 @@
+/*
+ *	editlev.cc
+ *	AYM 1998-09-06
+ */
+
+
+/*
+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 <time.h>
+#ifdef Y_X11
+#include <X11/Xlib.h>
+#endif
+#include "editlev.h"
+#include "editloop.h"
+#include "events.h"
+#include "game.h"
+#include "gfx.h"
+#include "levels.h"
+#include "patchdir.h"
+#include "wadfile.h"
+
+
+static void WriteYadexLog (const char *file, const char *level,
+ time_t *t0, time_t *t1);
+
+
+/*
+ *	find_level
+ *	Look in the master directory for levels that match
+ *	the name in <name_given>.
+ *
+ *	<name_given> can have one of the following formats :
+ *	
+ *	  [Ee]n[Mm]m      EnMm
+ *	  [Mm][Aa][Pp]nm  MAPnm
+ *	  n               MAP0n
+ *	  nm              Either EnMn or MAPnm
+ *	  ijk             EiMjk (Doom alpha 0.4 and 0.5)
+ *
+ *	Return:
+ *	- If <name_given> is either [Ee]n[Mm]m or [Mm][Aa][Pp]nm,
+ *	  - if the level was found, its canonical (uppercased)
+ *	    name in a freshly malloc'd buffer,
+ *	  - else, NULL.
+ *	- If <name_given> is either n or nm,
+ *	  - if either EnMn or MAPnm was found, the canonical name
+ *	    of the level found, in a freshly malloc'd buffer,
+ *	  - if none was found, <error_none>,
+ *	  - if the <name_given> is invalid, <error_invalid>,
+ *	  - if several were found, <error_non_unique>.
+ */
+char *find_level (const char *name_given)
+{
+// Is it a shorthand name ? ("1", "23", ...)
+if (al_sisnum (name_given)
+    && (atoi (name_given) <= 99
+      || atoi (name_given) <= 999 && yg_level_name == YGLN_E1M10))
+   {
+   int n = atoi (name_given);
+   char *name1 = (char *) malloc (7);
+   char *name2 = (char *) malloc (6);
+   if (n > 99)
+      sprintf (name1, "E%dM%02d", n / 100, n % 100);
+   else
+      sprintf (name1, "E%dM%d", n / 10, n % 10);
+   sprintf (name2, "MAP%02d", n);
+   int match1 = FindMasterDir (MasterDir, name1) != NULL;
+   int match2 = FindMasterDir (MasterDir, name2) != NULL;
+   if (match1 && ! match2)	// Found only ExMy
+      {
+      free (name2);
+      return name1;
+      }
+   else if (match2 && ! match1)	// Found only MAPxy
+      {
+      free (name1);
+      return name2;
+      }
+   else if (match1 && match2)	// Found both
+      {
+      free (name1);
+      free (name2);
+      return error_non_unique;
+      }
+   else				// Found none
+      {
+      free (name1);
+      free (name2);
+      return error_none;
+      }
+   }
+
+#if 1
+// Else look for <name_given>
+if (FindMasterDir (MasterDir, name_given))
+   return al_sdup (name_given);
+else
+   {
+   if (levelname2levelno (name_given))
+      return NULL;
+   else
+      return error_invalid;
+   }
+#else
+// If <name_given> is "[Ee]n[Mm]m" or "[Mm][Aa][Pp]nm", look for that
+if (levelname2levelno (name_given))
+   {
+   char *canonical_name = strdup (name_given);
+   for (char *p = canonical_name; *p; p++)
+      *p = toupper (*p);  // But shouldn't FindMasterDir() be case-insensitive ?
+   if (FindMasterDir (MasterDir, canonical_name))
+      return canonical_name;
+   else
+      {
+      free (canonical_name);
+      return NULL;
+      }
+   }
+return error_invalid;
+#endif
+}
+
+
+/*
+   the driving program
+*/
+
+void EditLevel (const char *levelname, bool newlevel)
+{
+ReadWTextureNames ();
+ReadFTextureNames ();
+patch_dir.refresh (MasterDir);
+if (InitGfx ())
+   return;
+/* Call init_input_status() as shortly as possible after the creation
+   of the window to minimize the risk of calling get_input_status(),
+   get_key(), have_key(), etc. with <is> still uninitialized. */
+init_input_status ();
+init_event ();
+CheckMouseDriver ();
+if (newlevel && ! levelname)  // "create"
+   {
+   EmptyLevelData (levelname);
+   MapMinX = -2000;
+   MapMinY = -2000;
+   MapMaxX = 2000;
+   MapMaxY = 2000;
+   Level = 0;
+   }
+else if (newlevel && levelname)  // "create <level_name>"
+   {
+   printf ("Sorry, \"create <level_name>\" is not implemented."
+	 " Try \"create\" without argument.\n");
+   TermGfx ();
+   return;
+   }
+else  // "edit <level_name>" or "edit"
+   {
+#if 0
+   if (levelname == 0 || ! levelname2levelno (levelname)
+    || ! FindMasterDir (MasterDir, levelname))
+      levelname = SelectLevel (atoi (levelname)); /* returns "" on Esc */
+   if (levelname2levelno (levelname))
+      {
+#endif
+      ClearScreen ();
+      if (ReadLevelData (levelname))
+	 {
+	 goto done;  // Failure!
+	 }
+#if 0
+      }
+#endif
+   }
+LogMessage (": Editing %s...\n", levelname ? levelname : "new level");
+
+// Set the name of the window
+{
+#define BUFSZ 100
+char buf[BUFSZ + 1];
+
+#ifdef OLD_TITLE
+al_scps (buf, "Yadex - ", BUFSZ);
+if (Level && Level->wadfile)
+   al_saps (buf, Level->wadfile->filename, BUFSZ);
+else
+   al_saps (buf, "New level", BUFSZ);
+if (Level)
+   {
+   al_saps (buf, " - ",           BUFSZ);
+   al_saps (buf, Level->dir.name, BUFSZ);
+   }
+else if (levelname)
+   {
+   al_saps (buf, " - ",     BUFSZ);
+   al_saps (buf, levelname, BUFSZ);
+   }
+#else
+al_scps (buf, "Yadex: ", BUFSZ);
+al_saps (buf, (levelname) ? levelname : "(null)", BUFSZ);
+#endif
+XStoreName (dpy, win, buf);
+#undef BUFSZ
+}
+
+{
+time_t t0, t1;
+time (&t0);
+EditorLoop (levelname);
+time (&t1);
+LogMessage (": Finished editing %s...\n", levelname ? levelname : "new level");
+if (Level && Level->wadfile)
+   {
+   const char *const file_name =
+      Level->wadfile ? Level->wadfile->pathname () : "(New level)";
+   WriteYadexLog (file_name, levelname, &t0, &t1);
+   }
+}
+done :
+TermGfx ();
+if (! Registered)
+   printf ("Please register the game"
+      " if you want to be able to save your changes.\n");
+
+ForgetLevelData ();
+/* forget the level pointer */
+Level = 0;
+ForgetWTextureNames ();
+ForgetFTextureNames ();
+}
+
+
+/*
+ *	WriteYadexLog - Keep track of time spent editing that wad file
+ *	FIXME should be in a separate module
+ */
+static void WriteYadexLog (const char *file, const char *level, time_t *t0, time_t *t1)
+{
+al_fspec_t logname;
+al_fdrv_t  drive;
+al_fpath_t path;
+al_fbase_t base;
+
+al_fana (file, drive, path, base, 0);
+sprintf (logname, "%s%s%s.yl", drive, path, base);
+
+/* if log file does not already exist, do _not_ create it */
+if (al_fnature (logname) == 1)
+   {
+   FILE *logfd;
+   logfd = fopen (logname, "a");
+   if (logfd)
+      {
+      struct tm *tm = localtime (t0);
+      fprintf (logfd, "%04d%02d%02d\tedit\t%s\t%ld\n",
+       tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday, level, (long)(*t1-*t0)/60);
+      fclose (logfd);
+      }
+   }
+}
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/editlev.h	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,9 @@
+/*
+ *	editlev.h
+ *	AYM 1998-09-06
+ */
+
+
+char *find_level (const char *name_given);
+void EditLevel (const char *, bool);
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/editloop.cc	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,2450 @@
+/*
+ *	editloop.cc
+ *	The main loop of the editor.
+ *	BW & RQ sometime in 1993 or 1994.
+ */
+
+
+/*
+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 <assert.h>
+#include "_edit.h"
+#include "checks.h"
+#include "dialog.h"
+#include "drawmap.h"
+#include "edisplay.h"
+#include "editgrid.h"
+#include "editloop.h"
+#include "editobj.h"
+#include "editsave.h"
+#include "editzoom.h"
+#include "entry.h"
+#include "entry2.h"
+#include "events.h"
+#include "gfx.h"
+#include "gfx2.h"	// show_character_set() show_pcolours()
+#include "gfx3.h"
+#include "gotoobj.h"
+#include "help2.h"
+#include "l_flags.h"
+#include "levels.h"
+#include "lists.h"
+#include "menubar.h"
+#include "menu.h"
+#include "modpopup.h"
+#include "objects.h"
+#include "objid.h"
+#include "palview.h"
+#include "prefer.h"
+#include "rgbbmp.h"
+#include "s_slice.h"
+#include "selbox.h"
+#include "selectn.h"
+#include "selpath.h"
+#include "spot.h"
+#include "t_flags.h"
+#include "t_spin.h"
+#include "x_centre.h"
+#include "x_exchng.h"
+#include "x_hover.h"
+#include "xref.h"
+
+#ifdef Y_X11
+#include <X11/Xlib.h>
+#endif
+
+
+
+static int zoom_fit (edit_t&);
+
+
+extern bool InfoShown;		/* should we display the info bar? */
+#if defined Y_BGI && defined CIRRUS_PATCH
+extern char HWCursor[];		/* Cirrus hardware cursor data */
+#endif /* Y_BGI && CIRRUS_PATCH */
+#ifdef DIALOG
+#endif
+
+
+static int menubar_out_y1;	/* FIXME */
+
+
+/* prototypes of private functions */
+static int SortLevels (const void *item1, const void *item2);
+
+/*
+ *	SelectLevel
+ *	Prompt the user for a level name (EnMn or MAPnm). The
+ *	name chosen must be present in the master directory
+ *	(iwad or pwads).
+ *
+ *	If <levelno> is 0, the level name can be picked from all
+ *	levels present in the master directory. If <levelno> is
+ *	non-zero, the level name can be picked only from those
+ *	levels in the master directory for which
+ *	levelname2levelno() % 1000 is equal to <levelno>. For
+ *	example, if <levelno> is equal to 12, only E1M2 and
+ *	MAP12 would be listed. This feature is not used anymore
+ *	because "e" now requires an argument and tends to deal
+ *	with ambiguous level names (like "12") itself.
+ */
+const char *SelectLevel (int levelno)
+{
+MDirPtr dir;
+static char name[WAD_NAME + 1]; /* AYM it was [7] previously */
+char **levels = 0;
+int n = 0;           /* number of levels in the dir. that match */
+
+get_levels_that_match:
+for (dir = MasterDir; dir; dir = dir->next)
+   {
+   if (levelname2levelno (dir->dir.name) > 0
+    && (levelno==0 || levelname2levelno (dir->dir.name) % 1000 == levelno))
+      {
+      if (n == 0)
+	 levels = (char **) GetMemory (sizeof (char *));
+      else
+	 levels = (char **) ResizeMemory (levels, (n + 1) * sizeof (char *));
+      levels[n] = dir->dir.name;
+      n++;
+      }
+   }
+if (n == 0 && levelno != 0)  /* In case no level matched levelno */
+   {
+   levelno = 0;               /* List ALL levels instead */
+   goto get_levels_that_match;
+   }
+/* So that InputNameFromList doesn't fail if you
+   have both EnMn's and MAPnn's in the master dir. */
+qsort (levels, n, sizeof (char *), SortLevels);
+al_scps (name, levels[0], sizeof name - 1);
+if (n == 1)
+   return name;
+InputNameFromList (-1, -1, "Level name :", n, levels, name);
+FreeMemory (levels);
+return name;
+}
+
+
+/*
+   compare 2 level names (for sorting)
+*/
+
+static int SortLevels (const void *item1, const void *item2)
+{
+/* FIXME should probably use y_stricmp() instead */
+return strcmp (*((const char * const *) item1),
+               *((const char * const *) item2));
+}
+
+
+// A table of the modes in the editor.
+typedef struct
+   {
+   i8 obj_type;		// Corresponding object type
+   i8 item_no;		// # of item to tick in the "View" menu
+   i8 menu_no;		// # of flavour of the "Misc op." menu
+   } editmode_t;
+
+const int NB_MODES = 4;
+
+static const editmode_t modes[NB_MODES] =
+   {
+   { OBJ_THINGS,   0, MBM_MISC_T },
+   { OBJ_LINEDEFS, 1, MBM_MISC_L },
+   { OBJ_VERTICES, 2, MBM_MISC_V },
+   { OBJ_SECTORS,  3, MBM_MISC_S },
+   };
+
+
+/*
+ *	obj_type_to_mode_no
+ *	Return the # of the mode that has this <obj_type>
+ */
+static int obj_type_to_mode_no (int obj_type)
+{
+int n;
+for (n = 0; n < NB_MODES; n++)
+   if (modes[n].obj_type == obj_type)
+      break;
+if (n == NB_MODES)
+   fatal_error ("no mode for obj_type %d", obj_type);
+return n;
+}
+
+
+// Used by the View menu
+bool mode_th (micbarg_t p) { return ((edit_t *) p)->obj_type == OBJ_THINGS;   }
+bool mode_l  (micbarg_t p) { return ((edit_t *) p)->obj_type == OBJ_LINEDEFS; }
+bool mode_v  (micbarg_t p) { return ((edit_t *) p)->obj_type == OBJ_VERTICES; }
+bool mode_s  (micbarg_t p) { return ((edit_t *) p)->obj_type == OBJ_SECTORS;  }
+
+
+/*
+  the editor main loop
+*/
+
+void EditorLoop (const char *levelname) /* SWAP! */
+{
+edit_t e;
+/* FIXME : all these variables should be moved to edit_t : */
+int    RedrawMap;
+bool   DragObject = false;
+int    oldbuttons;
+
+bool   StretchSelBox = false;  // FIXME apparently not used anymore...
+
+Objid object;			// The object under the pointer
+const Objid CANVAS (OBJ_NONE, OBJ_NO_CANVAS);
+
+memset (&e, 0, sizeof e);	/* Catch-all */
+e.move_speed          = 20;
+e.extra_zoom          = 0;
+// If you change this, don't forget to change
+// the initialisation of the menu bar below.
+e.obj_type            = OBJ_THINGS;
+e.global              = false;
+e.tool                = TOOL_NORMAL;
+e.grid_step           = 128;
+e.grid_step_min       = GridMin;
+e.grid_step_max       = GridMax;
+e.grid_step_locked    = 0;
+e.grid_shown          = 1;
+e.grid_snap           = 1;
+e.infobar_shown       = (bool) InfoShown;
+e.objinfo_shown       = true;
+e.show_object_numbers = false;
+e.show_things_squares = false;
+e.show_things_sprites = true;
+e.rulers_shown        = 0;
+e.clicked.nil ();
+//e.click_obj_no        = OBJ_NO_NONE;
+//e.click_obj_type      = -1;
+e.click_ctrl          = 0;
+e.highlighted.nil ();
+//e.highlight_obj_no    = OBJ_NO_NONE;
+//e.highlight_obj_type  = -1;
+e.Selected            = 0;
+e.selbox              = new selbox_c;
+e.edisplay            = new edisplay_c (&e);
+e.menubar             = new menubar_c;
+e.spot                = new spot_c;
+e.modpopup            = new modpopup_c;
+e.modal               = '\0';
+
+MadeChanges = 0;
+MadeMapChanges = 0;
+
+// Sane defaults
+Scale = 1.0;
+OrigX = 0;
+OrigY = 0;
+
+edit_zoom_init ();
+
+if (zoom_default == 0)
+   {
+   zoom_fit (e);
+   }
+else
+   {
+   int r = edit_set_zoom (&e, zoom_default / 100.0);
+   if (r == 0)
+      CenterMapAroundCoords ((MapMinX + MapMaxX) / 2, (MapMinY + MapMaxY) / 2);
+   }
+if (UseMouse)
+   {
+   ResetMouseLimits ();
+   SetMouseCoords (is.x, is.y);
+   ShowMousePointer ();
+#if defined Y_BGI && defined CIRRUS_PATCH
+   if (CirrusCursor)
+      {
+      SetHWCursorMap (HWCursor);
+      SetHWCursorPos (is.x, is.y);
+      }
+#endif /* Y_BGI && CIRRUS_PATCH */
+   oldbuttons = 0;
+   }
+else
+  FakeCursor = true;
+
+/* Create the menu bar */
+{
+e.menubar->compute_menubar_coords (0, 0, ScrMaxX, ScrMaxY);
+
+e.mb_menu[MBM_FILE] = new Menu (NULL,
+   "~Save",       YK_F2, 0,
+   "Save ~as...", YK_F3, 0,
+// "~Print",      YK_,   MIF_SACTIVE, false, 0,
+   "~Quit",       'q',   0,
+   NULL);
+
+e.mb_menu[MBM_EDIT] = new Menu (NULL,
+   "~Copy object(s)",          'o',    0,
+   "~Add object",              YK_INS, 0,
+   "~Delete object(s)",        YK_DEL, 0,
+   "~Exchange object numbers", 24,     0,
+   "~Preferences...",          YK_F5,  0,
+   "~Snap to grid",            'y',    MIF_VTICK, &e.grid_snap,		     0,
+   "~Lock grid step",          'z',    MIF_VTICK, &e.grid_step_locked,	     0,
+   NULL);
+
+// If you change the order of modes here, don't forget
+// to modify the <modes> array.
+e.mb_menu[MBM_VIEW] = new Menu (NULL,
+   "~Things",              't',        MIF_FTICK,   mode_th, (micbarg_t) &e, 0,
+   "~Linedefs & sidedefs", 'l',        MIF_FTICK,   mode_l,  (micbarg_t) &e, 0,
+   "~Vertices",            'v',        MIF_FTICK,   mode_v,  (micbarg_t) &e, 0,
+   "~Sectors",             's',        MIF_FTICK,   mode_s,  (micbarg_t) &e, 0,
+   "Global",               '\7',       MIF_VTICK,   &e.global,               0,
+   "~Next mode",           YK_TAB,     0,
+   "~Prev mode",           YK_BACKTAB, 0,
+   MI_SEPARATION,
+   "Zoom ~in",             '+',        0,
+   "Zoom ~out",            '-',        0,
+   "Extra ~zoom",          ' ',        MIF_VTICK,   &e.extra_zoom,           0,
+   "~Whole level",         '`',        0,
+   MI_SEPARATION,
+   "Show object numbers",  '&',        MIF_VTICK,   &e.show_object_numbers,  0,
+   "Show sprites",         '%',        MIF_VTICK,   &e.show_things_sprites,  0,
+   "Show ~grid",           'h',        MIF_VTICK,   &e.grid_shown,           0,
+   "Info bar",             YK_ALT+'i', MIF_VTICK,   &e.infobar_shown,        0,
+   "Object info boxes",    'i',        MIF_VTICK,   &e.objinfo_shown,        0,
+// "3D preview",           '3',        MIF_SACTIVE, false,                   0,
+   NULL);
+
+e.mb_menu[MBM_SEARCH] = new Menu (NULL,
+// "~Find/change",       YK_F4, MIF_SACTIVE, false, 0,
+// "~Repeat last find",  -1,    MIF_SACTIVE, false, 0,
+   "~Next object",       'n',   0,
+   "~Prev object",       'p',   0,
+   "~Jump to object...", 'j',   0,
+   NULL);
+
+e.mb_menu[MBM_MISC_L] = new Menu ("Misc. operations",
+   "Find first free ~tag number",		YK_, 0,
+   "~Rotate and scale linedefs...",		YK_, 0,
+   "Split linedefs (add new ~vertex)",		YK_, 0,
+   "~Split linedefs and sector",		YK_, 0,
+   "~Delete linedefs and join sectors",		YK_, 0,
+   "~Flip linedefs",				YK_, 0,
+   "S~wap sidedefs",				YK_, 0,
+   "Align textures (~Y offset)",		YK_, 0,
+   "Align textures (~X offset)...",		YK_, 0,
+   "Remove ~2nd sidedef (make single-sided)",	YK_, 0,
+   "Make rectangular ~nook (32x16)",		YK_, 0,
+   "Make rectangular ~boss (32x16)",		YK_, 0,
+   "Set ~length (move 1st vertex)...",		YK_, 0,
+   "Set length (move 2nd vertex)...",		YK_, 0,
+   "~Unlink 1st sidedef",			YK_, 0,
+   "Unlink 2nd sidedef",			YK_, 0,
+   "~Mirror horizontally",			YK_, 0,
+   "Mirror v~ertically",			YK_, 0,
+   "~Cut a slice out of a sector",		YK_, 0,
+   NULL);
+
+e.mb_menu[MBM_MISC_S] = new Menu ("Misc. operations",
+   "Find first free ~tag number",	YK_, 0,
+   "~Rotate and scale sectors...",	YK_, 0,
+   "Make ~door from sector",		YK_, 0,
+   "Make ~lift from sector",		YK_, 0,
+   "Distribute sector ~floor heights",	YK_, 0,
+   "Distribute sector ~ceiling heights",YK_, 0,
+   "R~aise or lower sectors...",	YK_, 0,
+   "~Brighten or darken sectors...",	YK_, 0,
+   "~Unlink room",			YK_, 0,
+   "~Mirror horizontally",		YK_, 0,
+   "Mirror ~vertically",		YK_, 0,
+   "~Swap flats",			YK_, 0,
+   NULL);
+
+e.mb_menu[MBM_MISC_T] = new Menu ("Misc. operations",
+   "Find first free ~tag number",	 YK_, 0,
+   "~Rotate and scale things...",	 YK_, 0,
+   "~Spin things 45° clockwise",	 'x', 0,
+   "Spin things 45° ~counter-clockwise", 'w', 0,
+   "~Mirror horizontally",		 YK_, 0,
+   "Mirror ~vertically",		 YK_, 0,
+   NULL);
+
+e.mb_menu[MBM_MISC_V] = new Menu ("Misc. operations",
+   "Find first free ~tag number",	YK_, 0,
+   "~Rotate and scale vertices...",	YK_, 0,
+   "~Delete vertex and join linedefs",	YK_, 0,
+   "~Merge several vertices into one",	YK_, 0,
+   "Add a linedef and ~split sector",	YK_, 0,
+   "Mirror ~horizontally",		YK_, 0,
+   "Mirror ~vertically",		YK_, 0,
+   NULL);
+
+e.mb_menu[MBM_OBJECTS] = new Menu ("Insert a pre-defined object",
+   "~Rectangle...",         YK_, 0,
+   "~Polygon (N sides)...", YK_, 0,
+   NULL);
+
+e.mb_menu[MBM_CHECK] = new Menu ("Check level consistency",
+   "~Number of objects",		YK_, 0,
+   "Check if all ~sectors are closed",	YK_, 0,
+   "Check all ~cross-references",	YK_, 0,
+   "Check for ~missing textures",	YK_, 0,
+   "Check ~texture names",		YK_, 0,
+   NULL);
+
+e.mb_menu[MBM_HELP] = new Menu (NULL,
+   "~Keyboard & mouse...", YK_F1,        0,
+   "~About Yadex...",      YK_ALT + 'a', 0,
+   NULL);
+
+e.mb_ino[MBI_FILE] =
+   e.menubar->add_item ("File",    0, 0, e.mb_menu[MBM_FILE]   );
+e.mb_ino[MBI_EDIT] =
+   e.menubar->add_item ("Edit",    0, 0, e.mb_menu[MBM_EDIT]   );
+e.mb_ino[MBI_VIEW] =
+   e.menubar->add_item ("View",    0, 0, e.mb_menu[MBM_VIEW]  );
+e.mb_ino[MBI_SEARCH] =
+   e.menubar->add_item ("Search",  0, 0, e.mb_menu[MBM_SEARCH] );
+e.mb_ino[MBI_MISC] =
+   e.menubar->add_item ("Misc",    0, 0, e.mb_menu[MBM_MISC_T] );
+e.mb_ino[MBI_OBJECTS] =
+   e.menubar->add_item ("Objects", 0, 0, e.mb_menu[MBM_OBJECTS]);
+e.mb_ino[MBI_CHECK] =
+   e.menubar->add_item ("Check",   0, 0, e.mb_menu[MBM_CHECK]  );
+e.mb_ino[MBI_HELP] =
+   e.menubar->add_item ("Help",    0, 1, e.mb_menu[MBM_HELP]   );
+
+menubar_out_y1 = 2 * BOX_BORDER + 2 * NARROW_VSPACING + FONTH - 1;  // FIXME
+}
+
+// FIXME this should come from the .ygd
+// instead of being hard-coded.
+Menu *menu_linedef_flags = new Menu (NULL,
+   "~Impassable",		YK_, 0,
+   "~Monsters cannot cross",	YK_, 0,
+   "~Double-sided",		YK_, 0,
+   "~Upper texture unpegged",	YK_, 0,
+   "~Lower texture unpegged",	YK_, 0,
+   "~Secret (shown as normal)",	YK_, 0,
+   "~Blocks sound",		YK_, 0,
+   "~Never shown on the map",	YK_, 0,
+   "~Always shown on the map",	YK_, 0,
+   "~Pass through [Boom]",	YK_, 0,  // Boom extension
+   "b1~0 0400h",		YK_, 0,  // Undefined
+   "b1~1 0800h",		YK_, 0,  // Undefined
+   "~Translucent [Strife]",	YK_, 0,  // Strife
+   "b1~3 2000h",		YK_, 0,  // Undefined
+   "b1~4 4000h",		YK_, 0,  // Undefined
+   "b1~5 8000h",		YK_, 0,  // Undefined
+   NULL);
+
+Menu *menu_thing_flags = new Menu (NULL,
+   "~Easy",			YK_, 0,
+   "Medi~um",			YK_, 0,
+   "~Hard",			YK_, 0,
+   "~Deaf",			YK_, 0,
+   "~Multiplayer",		YK_, 0,
+   "~Not in DM [Boom]",		YK_, 0,  // Boom extension
+   "Not in ~coop [Boom]", 	YK_, 0,  // Boom extension
+   "F~riendly [MBF]",		YK_, 0,  // MBF extension
+   "b~8  0100h",		YK_, 0,  // Undefined
+   "b~9  0200h",		YK_, 0,  // Undefined
+   "b1~0 0400h",		YK_, 0,  // Undefined
+   "b1~1 0800h",		YK_, 0,  // Undefined
+   "b1~2 1000h",		YK_, 0,  // Undefined
+   "b1~3 2000h",		YK_, 0,  // Undefined
+   "b1~4 4000h",		YK_, 0,  // Undefined
+   "b1~5 8000h",		YK_, 0,  // Undefined
+   NULL);
+
+/* AYM 1998-06-22
+   This is the big mean loop. I organized it in three main steps :
+
+   1. Update the display according to the current state of affairs.
+   2. Wait for the next event (key press, mouse click/motion, etc.).
+   3. Process this event and change states as appropriate.
+
+   This piece of code remembers a lot of state in various variables and
+   flags. Hope you can work your way through it. If you don't, don't
+   hesitate to ask me. You never know, I might help you to be even more
+   confused. ;-) */
+
+for (RedrawMap = 1; ; RedrawMap = 0)
+   {
+   int motion = 0;  // Initialized to silence GCC warning
+
+   /*
+    *  Step 1 -- Do all the displaying work
+    */
+
+#ifdef Y_BATCH
+   // Hold refresh until all events are processed
+   if (! has_event () && ! has_input_event ())
+      {
+#endif
+      if (e.highlighted ())				// FIXME
+	 e.edisplay->highlight_object (e.highlighted);	// Should
+      else						// be in
+	 e.edisplay->forget_highlight ();		// edisplay_c !
+
+   if (is.in_window)
+      e.spot->set (edit_mapx_snapped (&e, e.pointer_x),
+                   edit_mapy_snapped (&e, e.pointer_y));
+   else
+      e.spot->unset ();
+
+      e.edisplay->refresh ();
+      /* The display is now up to date */
+#ifdef Y_BATCH
+      }
+#endif
+
+
+   /*
+    *  Step 2 -- Get the next event
+    */
+
+   if (has_key_press_event ())
+      is.key = get_event ();
+   else
+      get_input_status ();
+   e.pointer_in_window = is.in_window;
+   if (is.in_window)
+      {
+      /* AYM 1998-07-04
+	 If the map coordinates of the pointer have changed,
+	 generate a pointer motion event. I don't like to do
+	 that but it makes things much simpler elsewhere. */
+      if (MAPX (is.x) != e.pointer_x || MAPY (is.y) != e.pointer_y)
+	 motion = 1;
+      else
+	 motion = 0;
+
+      e.pointer_x = MAPX (is.x);
+      e.pointer_y = MAPY (is.y);
+      obj_type_t t = e.global ? OBJ_ANY : e.obj_type;
+      GetCurObject (object, t, e.pointer_x, e.pointer_y);
+      }
+
+   /*
+    *  Step 3 -- Process the event
+    *  This section is (should be) a long list of elif's
+    */
+
+   /*
+    *	Step 3.1A -- If a pull-down menu is "on",
+    *	try to make it process the event.
+    */
+
+   if (e.menubar->pulled_down () >= 0)
+      {
+      int menu_no = e.menubar->pulled_down ();
+      Menu *menu = e.menubar->get_menu (menu_no);
+      int r = menu->process_event (&is);
+
+      if (r == MEN_CANCEL)
+	 {
+	 e.menubar->pull_down (-1);
+	 e.menubar->highlight (-1);
+         goto done;
+	 }
+
+      // The event was understood and processed normally
+      // by the menu event handler so we're done.
+      else if (r == MEN_OTHER)
+	 goto done;
+
+      // The event was not understood by the menu event
+      // handler so let's see what the normal event handler
+      // can do with it.
+      else if (r == MEN_INVALID)
+	 ;
+
+      else
+	 {
+	 e.menubar->pull_down (-1);
+	 e.menubar->highlight (-1);
+	 if (menu_no == e.mb_ino[MBI_MISC])
+	    {
+	    if (e.Selected)
+	       MiscOperations (e.obj_type, &e.Selected, r + 1);
+	    else
+	       {
+	       if (e.highlighted ())
+		  SelectObject (&e.Selected, e.highlighted.num);
+	       MiscOperations (e.obj_type, &e.Selected, r + 1);
+	       if (e.highlighted ())
+		  UnSelectObject (&e.Selected, e.highlighted.num);
+	       }
+	    e.highlighted.nil ();
+	    DragObject = false;
+	    StretchSelBox = false;
+	    RedrawMap = 1;
+	    }
+	 else if (menu_no == e.mb_ino[MBI_OBJECTS])
+            {
+	    /* code duplicated from 'F9' - I hate to do that */
+	    int savednum = NumLineDefs;
+	    InsertStandardObject (e.pointer_x, e.pointer_y, r + 1);
+	    if (NumLineDefs > savednum)
+	       {
+	       ForgetSelection (&e.Selected);
+	       e.obj_type = OBJ_LINEDEFS;
+	       for (int i = savednum; i < NumLineDefs; i++)
+		  SelectObject (&e.Selected, i);
+	       e.highlighted.nil ();
+	       DragObject = false;
+	       StretchSelBox = false;
+	       }
+	    RedrawMap = 1;
+            }
+	 else if (menu_no == e.mb_ino[MBI_CHECK])
+	    {
+	    if (r == 0)
+	       Statistics ();
+	    else if (r == 1)
+	       CheckSectors ();
+	    else if (r == 2)
+	       CheckCrossReferences ();
+	    else if (r == 3)
+	       CheckTextures ();
+	    else if (r == 4)
+	       CheckTextureNames ();
+	    }
+	 else
+	    send_event (menu->last_shortcut_key ());
+         goto done;
+	 }
+      }
+
+   /*
+    *	Step 3.1B -- If the "Misc operations" popup is on,
+    *	try to make it process the event.
+    */
+
+   else if (e.modpopup->get () == e.mb_menu[MBM_MISC_L]
+      || e.modpopup->get () == e.mb_menu[MBM_MISC_S]
+      || e.modpopup->get () == e.mb_menu[MBM_MISC_T]
+      || e.modpopup->get () == e.mb_menu[MBM_MISC_V])
+      {
+      int r = (e.modpopup->get ())->process_event (&is);
+
+      // [Esc] or click outside the popup menu. Close it.
+      if (r == MEN_CANCEL
+         || r == MEN_INVALID && is.key == YE_BUTL_PRESS)
+	 {
+         e.modpopup->unset ();
+         goto done2;
+	 }
+
+      // The event was understood and processed normally
+      // by the menu event handler so we're done.
+      else if (r == MEN_OTHER)
+	 goto done2;
+
+      // The event was not understood by the menu event
+      // handler so let's see what the normal event handler
+      // can do with it.
+      else if (r == MEN_INVALID)
+	 ;
+
+      else
+	 {
+         e.modpopup->unset ();
+	 if (e.Selected)
+	    MiscOperations (e.obj_type, &e.Selected, r + 1);
+	 else
+	    {
+	    if (e.highlighted ())
+	       SelectObject (&e.Selected, e.highlighted.num);
+	    MiscOperations (e.obj_type, &e.Selected, r + 1);
+	    if (e.highlighted ())
+	       UnSelectObject (&e.Selected, e.highlighted.num);
+	    }
+	 e.highlighted.nil ();
+	 DragObject = false;
+	 StretchSelBox = false;
+	 goto done2;
+	 }
+      }
+
+   /*
+    *	Step 3.1C -- If the "Insert standard object" popup is on,
+    *	try to make it process the event.
+    */
+
+   else if (e.modpopup->get () == e.mb_menu[MBM_OBJECTS])
+      {
+      int r = (e.modpopup->get ())->process_event (&is);
+
+      // [Esc] or click outside the popup menu. Close it.
+      if (r == MEN_CANCEL
+         || r == MEN_INVALID && is.key == YE_BUTL_PRESS)
+	 {
+         e.modpopup->unset ();
+         goto done2;
+	 }
+
+      // The event was understood and processed normally
+      // by the menu event handler so we're done.
+      else if (r == MEN_OTHER)
+	 goto done2;
+
+      // The event was not understood by the menu event
+      // handler so let's see what the normal event handler
+      // can do with it.
+      else if (r == MEN_INVALID)
+	 ;
+
+      else
+	 {
+         e.modpopup->unset ();
+	 int savednum = NumLineDefs;
+	 InsertStandardObject (e.pointer_x, e.pointer_y, r + 1);
+	 if (NumLineDefs > savednum)
+	    {
+	    ForgetSelection (&e.Selected);
+	    e.obj_type = OBJ_LINEDEFS;
+	    for (int i = savednum; i < NumLineDefs; i++)
+	       SelectObject (&e.Selected, i);
+	    e.highlighted.nil ();
+	    DragObject = false;
+	    StretchSelBox = false;
+	    }
+         goto done2;
+	 }
+      }
+
+   /*
+    *	Step 3.1D -- if the "Set/toggle/clear" linedef flag popup
+    *	is on, try to make it process the event.
+    */
+   else if (e.modpopup->get () == menu_linedef_flags)
+      {
+      int r = (e.modpopup->get ())->process_event (&is);
+
+      // [Esc] or click outside the popup menu. Close it.
+      if (r == MEN_CANCEL
+         || r == MEN_INVALID && is.key == YE_BUTL_PRESS)
+	 {
+         e.modpopup->unset ();
+         goto done2;
+	 }
+
+      // The event was understood and processed normally
+      // by the menu event handler so we're done.
+      else if (r == MEN_OTHER)
+	 goto done2;
+
+      // The event was not understood by the menu event
+      // handler so let's see what the normal event handler
+      // can do with it.
+      else if (r == MEN_INVALID)
+	 ;
+
+      else
+	 {
+         int op = -1;
+         e.modpopup->unset ();
+         if (e.modal == 's')
+            op = YO_SET;
+         else if (e.modal == 't')
+            op = YO_TOGGLE;
+         else if (e.modal == 'c')
+            op = YO_CLEAR;
+         else
+            fatal_error ("modal=%02X", e.modal);
+         if (! e.Selected)
+            {
+            SelectObject (&e.Selected, e.highlighted.num);
+            frob_linedefs_flags (e.Selected, op, r);
+            UnSelectObject (&e.Selected, e.highlighted.num);
+            }
+         else
+            {
+            frob_linedefs_flags (e.Selected, op, r);
+            }
+         goto done2;
+	 }
+      }
+
+   /*
+    *	Step 3.1E -- if the "Set/toggle/clear" thing flag popup
+    *	is on, try to make it process the event.
+    */
+   else if (e.modpopup->get () == menu_thing_flags)
+      {
+      int r = (e.modpopup->get ())->process_event (&is);
+
+      // [Esc] or click outside the popup menu. Close it.
+      if (r == MEN_CANCEL
+         || r == MEN_INVALID && is.key == YE_BUTL_PRESS)
+	 {
+         e.modpopup->unset ();
+         goto done2;
+	 }
+
+      // The event was understood and processed normally
+      // by the menu event handler so we're done.
+      else if (r == MEN_OTHER)
+	 goto done2;
+
+      // The event was not understood by the menu event
+      // handler so let's see what the normal event handler
+      // can do with it.
+      else if (r == MEN_INVALID)
+	 ;
+
+      else
+         {
+         int op = -1;
+         e.modpopup->unset ();
+         if (e.modal == 's')
+            op = YO_SET;
+         else if (e.modal == 't')
+            op = YO_TOGGLE;
+         else if (e.modal == 'c')
+            op = YO_CLEAR;
+         else
+            fatal_error ("modal=%02X", e.modal);
+         if (! e.Selected)
+            {
+            SelectObject (&e.Selected, e.highlighted.num);
+            frob_things_flags (e.Selected, op, r);
+            UnSelectObject (&e.Selected, e.highlighted.num);
+            }
+         else
+            {
+            frob_things_flags (e.Selected, op, r);
+            }
+         goto done2;
+	 }
+      }
+
+   /*
+    *	Step 3.2 -- "Normal" event handling
+    */
+
+   /*
+    *	Step 3.2.1 -- Non keyboard events
+    */
+
+   if (is.key == YE_EXPOSE)
+      {
+      RedrawMap = 1;
+      goto done2;
+      }
+
+   else if (is.key == YE_RESIZE)
+      {
+      SetWindowSize (is.width, is.height);
+      e.menubar->compute_menubar_coords (0, 0, ScrMaxX, ScrMaxY);
+      RedrawMap = 1;
+      goto done2;
+      }
+
+   // To prevent normal handling when a popup menu is on.
+   if (e.modpopup->get () != 0)
+      {
+      goto done2;
+      }
+
+   /*
+    *	Step 3.2.2 -- Mouse events
+    */
+
+
+   // Clicking on an item of the menu bar
+   // pulls down the corresponding menu.
+   else if (is.key == YE_BUTL_PRESS
+      && e.menubar->is_on_menubar_item (is.x, is.y) >= 0)
+      {
+      int itemno;
+
+      e.clicked.nil ();
+      itemno = e.menubar->is_on_menubar_item (is.x, is.y);
+      if (itemno >= 0)
+         e.menubar->pull_down (itemno);
+      else
+         Beep ();
+      goto done;
+      }
+
+   /* Clicking on an empty space starts a new selection box.
+      Unless [Ctrl] is pressed, it also clears the current selection. */
+   else if (is.key == YE_BUTL_PRESS
+	 && e.tool == TOOL_NORMAL
+	 && object.is_nil ())
+      {
+      e.menubar->highlight (-1);  // Close any open menu
+      e.clicked    = CANVAS;
+      e.click_ctrl = is.ctrl;
+      if (! is.ctrl)
+         {
+         ForgetSelection (&e.Selected);
+         RedrawMap = 1;
+         }
+      e.selbox->set_1st_corner (e.pointer_x, e.pointer_y);
+      e.selbox->set_2nd_corner (e.pointer_x, e.pointer_y);
+      }
+
+   /* Clicking on an unselected object unselects
+      everything but that object. Additionally,
+      we write the number of the object in case
+      the user is about to drag it. */
+   else if (is.key == YE_BUTL_PRESS && ! is.ctrl
+	 && e.tool == TOOL_NORMAL
+	 && ! IsSelected (e.Selected, object.num))
+      {
+      e.menubar->highlight (-1);  // Close any open menu
+      e.clicked        = object;
+      e.click_ctrl     = 0;
+      e.click_time     = is.time;
+      ForgetSelection (&e.Selected);
+      SelectObject (&e.Selected, object.num);
+      /* I don't like having to do that */
+      if (object.type == OBJ_THINGS && object ())
+	 MoveObjectsToCoords (object.type, 0,
+            Things[object.num].xpos, Things[object.num].ypos, 0);
+      else if (object.type == OBJ_VERTICES && object ())
+	 MoveObjectsToCoords (object.type, 0,
+            Vertices[object.num].x, Vertices[object.num].y, 0);
+      else
+	 MoveObjectsToCoords (object.type, 0,
+            e.pointer_x, e.pointer_y, e.grid_snap ? e.grid_step : 0);
+      RedrawMap = 1;
+      }
+
+   /* Second click of a double click on an object */
+   else if (is.key == YE_BUTL_PRESS && ! is.ctrl
+	 && e.tool == TOOL_NORMAL
+	 && IsSelected (e.Selected, object.num)
+	 && object  == e.clicked
+	 && is.time - e.click_time <= (unsigned long) double_click_timeout)
+      {
+      // Very important! If you don't do that, the release of the
+      // click that closed the properties menu will drag the object.
+      e.clicked.nil ();
+      send_event (YK_RETURN);
+      goto done;
+      }
+
+   /* Clicking on a selected object does nothing ;
+      the user might want to drag the selection. */
+   else if (is.key == YE_BUTL_PRESS && ! is.ctrl
+	 && e.tool == TOOL_NORMAL
+	 && IsSelected (e.Selected, object.num))
+      {
+      e.menubar->highlight (-1);  // Close any open menu
+      e.clicked        = object;
+      e.click_ctrl     = 0;
+      e.click_time     = is.time;
+      /* I don't like having to do that */
+      if (object.type == OBJ_THINGS && object ())
+	 MoveObjectsToCoords (object.type, 0,
+            Things[object.num].xpos, Things[object.num].ypos, 0);
+      else if (object.type == OBJ_VERTICES && object ())
+	 MoveObjectsToCoords (object.type, 0,
+            Vertices[object.num].x, Vertices[object.num].y, 0);
+      else
+	 MoveObjectsToCoords (object.type, 0,
+            e.pointer_x, e.pointer_y, e.grid_snap ? e.grid_step : 0);
+      }
+
+   /* Clicking on selected object with [Ctrl] pressed unselects it.
+      Clicking on unselected object with [Ctrl] pressed selects it. */
+   else if (is.key == YE_BUTL_PRESS && is.ctrl
+	 && e.tool == TOOL_NORMAL
+	 && object ())
+      {
+      e.menubar->highlight (-1);  // Close any open menu
+      e.clicked        = object;
+      e.click_ctrl     = 1;
+      if (IsSelected (e.Selected, object.num))
+	UnSelectObject (&e.Selected, object.num);
+      else
+	SelectObject (&e.Selected, object.num);
+      RedrawMap = 1;
+      }
+
+   /* TOOL_SNAP_VERTEX */
+   else if (is.key == YE_BUTL_PRESS
+	    && e.tool == TOOL_SNAP_VERTEX
+	    && e.obj_type == OBJ_VERTICES
+	    && object ()
+	    // Can't delete vertex that is referenced by the selection
+	    && ! IsSelected (e.Selected, object.num))
+      {
+      printf ("SNAP %d\n", (int) object.num);
+      SelPtr list = 0;
+      SelectObject (&list, object.num);
+      DeleteVerticesJoinLineDefs (list);
+      ForgetSelection (&list);
+      RedrawMap = 1;
+      }
+
+   /* Clicking anywhere else closes the pull-down menus. */
+   else if (is.key == YE_BUTL_PRESS)
+      e.menubar->highlight (-1);  // Close any open menu
+
+   /* Releasing the button while there was a selection box
+      causes all the objects within the box to be selected. */
+   // FIXME : should call this automatically when switching tool
+   else if (is.key == YE_BUTL_RELEASE
+	 && e.tool == TOOL_NORMAL
+	 && e.clicked == CANVAS)
+      {
+      int x1, y1, x2, y2;
+      e.selbox->get_corners (&x1, &y1, &x2, &y2);
+      SelectObjectsInBox (&e.Selected, e.obj_type, x1, y1, x2, y2);
+      e.selbox->unset_corners ();
+      RedrawMap = 1;
+      }
+
+   /* Releasing the button while dragging : drop the selection. */
+   // FIXME : should call this automatically when switching tool
+   else if (is.key == YE_BUTL_RELEASE
+	 && e.tool == TOOL_NORMAL
+	 && e.clicked ())
+      {
+      if (AutoMergeVertices (&e.Selected, e.obj_type, 'm'))
+         RedrawMap = 1;
+      }
+
+   // Moving the pointer with the left button pressed
+   // after clicking on an item of the menu bar : pull
+   // down menus as the pointer passes over them.
+   else if (is.key == YE_MOTION
+      && e.tool == TOOL_NORMAL
+      && is.butl
+      && ! e.clicked () && ! (e.clicked == CANVAS))
+      {
+      int itemno = e.menubar->is_on_menubar_item (is.x, is.y);
+      if (itemno >= 0)
+         e.menubar->pull_down (itemno);
+      goto done;
+      }
+
+   /* Moving the pointer with the left button pressed
+      and a selection box exists : move the second
+      corner of the selection box. */
+   else if ((is.key == YE_MOTION || motion)
+      && e.tool == TOOL_NORMAL
+      && is.butl && e.clicked == CANVAS)
+      {
+      e.selbox->set_2nd_corner (e.pointer_x, e.pointer_y);
+      }
+
+   /* Moving the pointer with the left button pressed
+      but no selection box exists and [Ctrl] was not
+      pressed when the button was pressed :
+      drag the selection. */
+   else if (motion
+      && e.tool == TOOL_NORMAL
+      && is.butl
+      && e.clicked ()
+      && ! e.click_ctrl)
+      {
+      if (! e.Selected)
+	 {
+	 SelectObject (&e.Selected, e.clicked.num);
+	 if (MoveObjectsToCoords (e.clicked.type, e.Selected,
+            e.pointer_x, e.pointer_y, e.grid_snap ? e.grid_step : 0))
+	    RedrawMap = 1;
+	 ForgetSelection (&e.Selected);
+	 }
+      else
+	 if (MoveObjectsToCoords (e.clicked.type, e.Selected,
+            e.pointer_x, e.pointer_y, e.grid_snap ? e.grid_step : 0))
+	    RedrawMap = 1;
+      }
+
+   /* AYM : added is.in_window */
+   if (is.in_window && ! is.butl && ! is.shift)
+      {
+      /* Check if there is something near the pointer */
+      e.highlighted = object;
+      }
+
+   /*
+    *	Step 3.2.3 -- Keyboard events
+    */
+
+   if (event_is_key (is.key)
+      || is.key == YE_WHEEL_UP
+      || is.key == YE_WHEEL_DOWN)
+      {
+      if (is.key == YK_LEFT && e.menubar->highlighted () >= 0)
+         {
+         int new_item = e.menubar->highlighted () - 1;
+         if (new_item < 0)
+            new_item = e.mb_ino[MBI_HELP];
+         e.menubar->pull_down (new_item);
+         RedrawMap = 1;
+         }
+
+      else if (is.key == YK_RIGHT && e.menubar->highlighted () >= 0)
+         {
+         int new_item = e.menubar->highlighted () + 1;
+         if (new_item > e.mb_ino[MBI_HELP])
+            new_item = 0;
+         e.menubar->pull_down (new_item);
+         RedrawMap = 1;
+         }
+
+      else if (is.key == YK_ALT + 'f')
+         e.menubar->pull_down (e.mb_ino[MBI_FILE]);
+
+      else if (is.key == YK_ALT + 'e')
+         e.menubar->pull_down (e.mb_ino[MBI_EDIT]);
+
+      else if (is.key == YK_ALT + 's')
+	 e.menubar->pull_down (e.mb_ino[MBI_SEARCH]);
+
+      else if (is.key == YK_ALT + 'v')
+	 e.menubar->pull_down (e.mb_ino[MBI_VIEW]);
+
+      else if (is.key == YK_ALT + 'm')
+	 e.menubar->pull_down (e.mb_ino[MBI_MISC]);
+
+      else if (is.key == YK_ALT + 'o')
+	 e.menubar->pull_down (e.mb_ino[MBI_OBJECTS]);
+
+      else if (is.key == YK_ALT + 'c')
+	 e.menubar->pull_down (e.mb_ino[MBI_CHECK]);
+
+      else if (is.key == YK_ALT + 'h')
+	 e.menubar->pull_down (e.mb_ino[MBI_HELP]);
+
+
+      // [Ctrl][L]: force redraw
+      else if (is.key == '\f')
+	{
+	RedrawMap = 1;
+	}
+
+      // [Esc], [q]: close
+      else if (is.key == YK_ESC || is.key == 'q')
+         {
+	 if (DragObject)
+	    DragObject = false;
+	 else if (StretchSelBox)
+	    StretchSelBox = false;
+	 else
+	    {
+	    ForgetSelection (&e.Selected);
+	    if (!MadeChanges
+	     || Confirm (-1, -1, "You have unsaved changes."
+				" Do you really want to quit?", 0))
+	       break;
+	    RedrawMap = 1;
+	    }
+         }
+
+      // [F1]: pop up "Help" window
+      else if (is.key == YK_F1) /* 'F1' */
+         {
+	 DisplayHelp ();
+	 RedrawMap = 1;
+         }
+
+      // [Alt][a]: pop up the "About..." window
+      else if (is.key == YK_ALT + 'a')
+         {
+         about_yadex ();
+         RedrawMap = 1;
+         }
+
+      // [Shift][F1]: save a screen shot into yadex.gif.
+      // FIXME doesn't work in the Unix port
+      else if (is.key == YK_F1 + YK_SHIFT)
+	 {
+	 Rgbbmp b;
+	 window_to_rgbbmp (0, 0, (int) ScrMaxX + 1, (int) ScrMaxY + 1, b);
+	 rgbbmp_to_rawppm (b, "yadex.ppm");
+	 //ScreenShot ();
+	 }
+
+      // [Shift][F2]: undocumented--test of Entry2
+      else if (is.key == YK_F2 + YK_SHIFT)
+	 {
+	 char buf1[10];
+	 char buf2[30];
+	 char buf3[20];
+	 strcpy (buf1, "buf1");
+	 strcpy (buf2, "buf2");
+	 strcpy (buf3, "buf3");
+	 Entry2 e ("Title of window", "Buf 1%*sBuf 2%*sBuf 3%*s",
+	     sizeof buf1 - 1, buf1,
+	     sizeof buf2 - 1, buf2,
+	     sizeof buf3 - 1, buf3);
+	 e.loop ();
+	 printf ("bufs: \"%s\", \"%s\", \"%s\"\n", buf1, buf2, buf3);
+	 RedrawMap = 1;
+	 }
+
+      /* [F2] save level into pwad, prompt for the file name
+         every time but keep the same level name. */
+      else if (is.key == YK_F2 && Registered)
+         {
+	 if (! CheckStartingPos ())
+	    goto cancel_save;
+	 char *outfile;
+	 const char *newlevelname;
+	 if (levelname)
+	    newlevelname = levelname;
+	 else
+	    {
+	    newlevelname = SelectLevel (0);
+	    if (! *newlevelname)
+	       goto cancel_save;
+	    }
+	 outfile = GetWadFileName (newlevelname);
+	 if (! outfile)
+	    goto cancel_save;
+	 SaveLevelData (outfile, newlevelname);
+	 levelname = newlevelname;
+	 // Sigh. Shouldn't have to do that. Level must die !
+	 Level = FindMasterDir (MasterDir, levelname);
+cancel_save:
+	 RedrawMap = 1;
+         }
+
+      /* [F3] save level into pwad, prompt for the file name and
+         level name. */
+      else if (is.key == YK_F3 && Registered)
+         {
+	 char *outfile;
+	 const char *newlevelname;
+	 MDirPtr newLevel, oldl, newl;
+
+	 if (! CheckStartingPos ())
+	    goto cancel_save_as;
+	 newlevelname = SelectLevel (0);
+	 if (! *newlevelname)
+	    goto cancel_save_as;
+	 if (! levelname || y_stricmp (newlevelname, levelname))
+	    {
+	    /* horrible but it works... */
+	    // Horrible indeed -- AYM 1999-07-30
+	    newLevel = FindMasterDir (MasterDir, newlevelname);
+	    if (! newLevel)
+	       nf_bug ("newLevel is NULL");  // Debatable ! -- AYM 2001-05-29
+	    if (Level)  // If new level ("create" command), Level is NULL
+	       {
+	       oldl = Level;
+	       newl = newLevel;
+	       for (int m = 0; m < 11; m++)
+		  {
+		  newl->wadfile = oldl->wadfile;
+		  if (m > 0)
+		     newl->dir = oldl->dir;
+		  /*
+		  if (!fncmp (outfile, oldl->wadfile->filename))
+		     {
+		     oldl->wadfile = WadFileList;
+		     oldl->dir = lost...
+		     }
+		  */
+		  oldl = oldl->next;
+		  newl = newl->next;
+		  }
+	       }
+	    Level = newLevel;
+	    }
+	 outfile = GetWadFileName (newlevelname);
+	 if (! outfile)
+	    goto cancel_save_as;
+	 SaveLevelData (outfile, newlevelname);
+	 levelname = newlevelname;
+cancel_save_as:
+	 RedrawMap = 1;
+         }
+
+      // [F5]: pop up the "Preferences" menu
+      else if (is.key == YK_F5
+         && e.menubar->highlighted () < 0)
+         {
+	 Preferences (-1, -1);
+	 RedrawMap = 1;
+         }
+
+      // [a]: pop up the "Set flag" menu
+      else if (is.key == 'a'
+         && e.menubar->highlighted () < 0
+         && (e.Selected || e.highlighted ()))
+         {
+         e.modal = 's';  // Set
+         if (e.obj_type == OBJ_LINEDEFS)
+            {
+            menu_linedef_flags->set_title ("Set linedef flag");
+            e.modpopup->set (menu_linedef_flags, 0);
+            }
+         else if (e.obj_type == OBJ_THINGS)
+            {
+            menu_thing_flags->set_title ("Set thing flag");
+            e.modpopup->set (menu_thing_flags, 0);
+            }
+         }
+
+      // [b]: pop up the "Toggle flag" menu
+      else if (is.key == 'b'
+         && e.menubar->highlighted () < 0
+         && (e.Selected || e.highlighted ()))
+         {
+         e.modal = 't';  // Toggle
+         if (e.obj_type == OBJ_LINEDEFS)
+            {
+            menu_linedef_flags->set_title ("Toggle linedef flag");
+            e.modpopup->set (menu_linedef_flags, 0);
+            }
+         else if (e.obj_type == OBJ_THINGS)
+            {
+            menu_thing_flags->set_title ("Toggle thing flag");
+            e.modpopup->set (menu_thing_flags, 0);
+            }
+         }
+
+      // [c]: pop up the "Clear flag" menu
+      else if (is.key == 'c'
+         && e.menubar->highlighted () < 0
+         && (e.Selected || e.highlighted ()))
+         {
+         e.modal = 'c';  // Clear;
+         if (e.obj_type == OBJ_LINEDEFS)
+            {
+            menu_linedef_flags->set_title ("Clear linedef flag");
+            e.modpopup->set (menu_linedef_flags, 0);
+            }
+         else if (e.obj_type == OBJ_THINGS)
+            {
+            menu_thing_flags->set_title ("Clear thing flag");
+            e.modpopup->set (menu_thing_flags, 0);
+            }
+         }
+
+      // [F8]: pop up the "Misc. operations" menu
+      else if (is.key == YK_F8
+         && e.menubar->highlighted () < 0)
+         {
+         e.modpopup->set (e.menubar->get_menu (MBI_MISC), 1);
+         }
+
+      // [F9]: pop up the "Insert a standard object" menu
+      else if (is.key == YK_F9
+         && e.menubar->highlighted () < 0)
+         {
+         e.modpopup->set (e.menubar->get_menu (MBI_OBJECTS), 1);
+         }
+
+      // [F10]: pop up the "Checks" menu
+      else if (is.key == YK_F10
+         && e.menubar->highlighted () < 0)
+         {
+	 CheckLevel (-1, -1);
+	 RedrawMap = 1;
+         }
+
+      // [Alt][i]: show/hide the info bar
+      else if (is.key == YK_ALT + 'i')
+         {
+	 e.infobar_shown = !e.infobar_shown;
+	 RedrawMap = 1;
+         }
+
+      // [i]: show/hide the object info boxes
+      else if (is.key == 'i')
+         {
+	 e.objinfo_shown = !e.objinfo_shown;
+	 RedrawMap = 1;
+	 }
+
+      // [+], [=], wheel: zooming in
+      else if (is.key == '+' || is.key == '=' || is.key == YE_WHEEL_UP)
+         {
+         int r = edit_zoom_in (&e);
+	 if (r == 0)
+	   RedrawMap = 1;
+         }
+
+      // [-], [_], wheel: zooming out
+      else if (is.key == '-' || is.key == '_' || is.key == YE_WHEEL_DOWN)
+         {
+         int r = edit_zoom_out (&e);
+	 if (r == 0)
+	   RedrawMap = 1;
+         }
+
+      // [1] - [9], [0]: set the zoom factor
+      else if (is.key >= '0' && is.key <= '9')
+         {
+         int r = edit_set_zoom (&e, digit_zoom_factors[dectoi(is.key)]);
+	 if (r == 0)
+	   RedrawMap = 1;
+         }
+
+      // [']: centre window on centre of map
+      else if (is.key == '\'')
+         {
+	 update_level_bounds ();
+         CenterMapAroundCoords ((MapMinX + MapMaxX) / 2,
+            (MapMinY + MapMaxY) / 2);
+         RedrawMap = 1;
+         }
+
+      // [`]: centre window on centre of map
+      // and set zoom to view the entire map
+      else if (is.key == '`')
+         {
+	 int r = zoom_fit (e);
+	 if (r == 0)
+	   RedrawMap = 1;
+         }
+
+#if 0
+      /* user wants to move */
+      else if (is.key == YK_UP && (is.y - e.move_speed) >= 0)
+         {
+	 if (UseMouse)
+	    SetMouseCoords (is.x, is.y - e.move_speed);
+	 else
+	    is.y -= e.move_speed;
+         }
+      else if (is.key == YK_DOWN && (is.y + e.move_speed) <= ScrMaxY)
+         {
+	 if (UseMouse)
+	    SetMouseCoords (is.x, is.y + e.move_speed);
+	 else
+	    is.y += e.move_speed;
+         }
+      else if (is.key == YK_LEFT && (is.x - e.move_speed) >= 0)
+         {
+	 if (UseMouse)
+	    { 
+	    SetMouseCoords (is.x - e.move_speed, is.y);
+	    LogMessage ("dec'd px=%d by %d\n", is.x, e.move_speed); /* AYM */
+	    }
+	 else
+	    is.x -= e.move_speed;
+         }
+      else if (is.key == YK_RIGHT)
+	 {
+	 if ((is.x + e.move_speed) <= ScrMaxX)
+	    {
+	    if (UseMouse)
+	       {
+	       SetMouseCoords (is.x + e.move_speed, is.y);
+	       LogMessage ("inc'd px=%d by %d\n", is.x, e.move_speed); /* AYM */
+	       }
+	    else
+	       {
+	       is.x += e.move_speed;
+	       LogMessage ("inc'd px by %d\n",  e.move_speed); /* AYM */
+	       }
+	    }
+	 else
+	    LogMessage ("px=%d ms=%d smx=%d\n", is.x, e.move_speed, ScrMaxX);
+	 }
+#endif
+
+      // [Left], [Right], [Up], [Down]:
+      // scroll <scroll_less> percents of a screenful.
+      else if (is.key == YK_LEFT && MAPX (ScrCenterX) > -20000)
+         {
+	 OrigX -= (int) ((double) ScrMaxX * scroll_less / 100 / Scale);
+	 RedrawMap = 1;
+	 }
+      else if (is.key == YK_RIGHT && MAPX (ScrCenterX) < 20000)
+         {
+	 OrigX += (int) ((double) ScrMaxX * scroll_less / 100 / Scale);
+	 RedrawMap = 1;
+	 }
+      else if (is.key == YK_UP && MAPY (ScrCenterY) < 20000)
+         {
+	 OrigY += (int) ((double) ScrMaxY * scroll_less / 100 / Scale);
+	 RedrawMap = 1;
+	 }
+      else if (is.key == YK_DOWN && MAPY (ScrCenterY) > -20000)
+         {
+	 OrigY -= (int) ((double) ScrMaxY * scroll_less / 100 / Scale);
+	 RedrawMap = 1;
+	 }
+
+      // [Pgup], [Pgdn], [Home], [End]:
+      // scroll <scroll_more> percents of a screenful.
+      else if (is.key == YK_PU && MAPY (ScrCenterY) < /*MapMaxY*/ 20000)
+	 {
+	 OrigY += (int) ((double) ScrMaxY * scroll_more / 100 / Scale);
+	 RedrawMap = 1;
+	 }
+      else if (is.key == YK_PD && MAPY (ScrCenterY) > /*MapMinY*/ -20000)
+	 {
+	 OrigY -= (int) ((double) ScrMaxY * scroll_more / 100 / Scale);
+	 RedrawMap = 1;
+	 }
+      else if (is.key == YK_HOME && MAPX (ScrCenterX) > /*MapMinX*/ -20000)
+	 {
+	 OrigX -= (int) ((double) ScrMaxX * scroll_more / 100 / Scale);
+	 RedrawMap = 1;
+	 }
+      else if (is.key == YK_END && MAPX (ScrCenterX) < /*MapMaxX*/ 20000)
+	 {
+	 OrigX += (int) ((double) ScrMaxX * scroll_more / 100 / Scale);
+	 RedrawMap = 1;
+	 }
+
+#if 0
+      /* user wants to change the movement speed */
+      else if (is.key == ' ')
+	 e.move_speed = e.move_speed == 1 ? 20 : 1;
+#endif
+      else if (is.key == ' ')
+         {
+         e.extra_zoom = ! e.extra_zoom;
+         edit_set_zoom (&e, Scale * (e.extra_zoom ? 4 : 0.25));
+         RedrawMap = 1;
+         }
+
+      // [Tab], [l], [s], [t], [v]: switch mode
+      else if (is.key == YK_TAB || is.key == YK_BACKTAB
+       || is.key == 't' || is.key == 'v' || is.key == 'l' || is.key == 's')
+	 {
+         int    old_mode;
+         int    new_mode = -1;
+	 int    PrevMode = e.obj_type;
+	 SelPtr NewSel;
+
+         // What's the number of the current mode ?
+         old_mode = obj_type_to_mode_no (e.obj_type);
+
+         // What's the number of the new mode ?
+	 if (is.key == YK_TAB)				// [Tab]
+            new_mode = (old_mode + 1) % NB_MODES;
+	 else if (is.key == YK_BACKTAB)			// [Shift]-[Tab]
+            new_mode = old_mode == 0 ? NB_MODES - 1 : old_mode - 1;
+	 else
+	    {
+	    if (is.key == 't')
+	       new_mode = obj_type_to_mode_no (OBJ_THINGS);
+	    else if (is.key == 'v')
+	       new_mode = obj_type_to_mode_no (OBJ_VERTICES);
+	    else if (is.key == 'l')
+	       new_mode = obj_type_to_mode_no (OBJ_LINEDEFS);
+	    else if (is.key == 's')
+	       new_mode = obj_type_to_mode_no (OBJ_SECTORS);
+            else
+               fatal_error ("changing mode with %04X", is.key);
+	    /* unselect all */
+	    ForgetSelection (&e.Selected);
+	    }
+
+         // Set the object type according to the new mode.
+         e.obj_type = modes[new_mode].obj_type;
+
+         // Change the flavour of the "Misc" menu.
+         e.menubar->set_menu (e.mb_ino[MBI_MISC],
+            e.mb_menu[modes[new_mode].menu_no]);
+
+	 /* special cases for the selection list... */
+	 if (e.Selected)
+	    {
+	    /* select all linedefs bound to the selected sectors */
+	    if (PrevMode == OBJ_SECTORS && e.obj_type == OBJ_LINEDEFS)
+	       {
+	       int l, sd;
+
+	       ObjectsNeeded (OBJ_LINEDEFS, OBJ_SIDEDEFS, 0);
+	       NewSel = 0;
+	       for (l = 0; l < NumLineDefs; l++)
+	          {
+		  sd = LineDefs[l].sidedef1;
+		  if (sd >= 0 && IsSelected (e.Selected, SideDefs[sd].sector))
+		     SelectObject (&NewSel, l);
+		  else
+		     {
+		     sd = LineDefs[l].sidedef2;
+		     if (sd >= 0 && IsSelected (e.Selected, SideDefs[sd].sector))
+			SelectObject (&NewSel, l);
+		     }
+	          }
+	       ForgetSelection (&e.Selected);
+	       e.Selected = NewSel;
+	    }
+	    /* select all Vertices bound to the selected linedefs */
+	    else if (PrevMode == OBJ_LINEDEFS && e.obj_type == OBJ_VERTICES)
+	       {
+	       ObjectsNeeded (OBJ_LINEDEFS, 0);
+	       NewSel = 0;
+	       while (e.Selected)
+	          {
+		  if (!IsSelected (NewSel, LineDefs[e.Selected->objnum].start))
+		     SelectObject (&NewSel, LineDefs[e.Selected->objnum].start);
+		  if (!IsSelected (NewSel, LineDefs[e.Selected->objnum].end))
+		     SelectObject (&NewSel, LineDefs[e.Selected->objnum].end);
+		  UnSelectObject (&e.Selected, e.Selected->objnum);
+	          }
+	       e.Selected = NewSel;
+	       }
+	    /* select all sectors that have their linedefs selected */
+	    else if (PrevMode == OBJ_LINEDEFS && e.obj_type == OBJ_SECTORS)
+	       {
+	       int l, sd;
+
+	       ObjectsNeeded (OBJ_LINEDEFS, OBJ_SIDEDEFS, 0);
+	       NewSel = 0;
+	       /* select all sectors... */
+	       for (l = 0; l < NumSectors; l++)
+		  SelectObject (&NewSel, l);
+	       /* ... then unselect those that should not be in the list */
+	       for (l = 0; l < NumLineDefs; l++)
+		  if (!IsSelected (e.Selected, l))
+		     {
+		     sd = LineDefs[l].sidedef1;
+		     if (sd >= 0)
+			UnSelectObject (&NewSel, SideDefs[sd].sector);
+		     sd = LineDefs[l].sidedef2;
+		     if (sd >= 0)
+		       UnSelectObject (&NewSel, SideDefs[sd].sector);
+		     }
+	       ForgetSelection (&e.Selected);
+	       e.Selected = NewSel;
+	       }
+	    /* select all linedefs that have both ends selected */
+	    else if (PrevMode == OBJ_VERTICES && e.obj_type == OBJ_LINEDEFS)
+	       {
+	       int l;
+
+	       ObjectsNeeded (OBJ_LINEDEFS, 0);
+	       NewSel = 0;
+	       for (l = 0; l < NumLineDefs; l++)
+		  if (IsSelected (e.Selected, LineDefs[l].start)
+		   && IsSelected (e.Selected, LineDefs[l].end))
+		     SelectObject (&NewSel, l);
+	       ForgetSelection (&e.Selected);
+	       e.Selected = NewSel;
+	       }
+	    /* unselect all */
+	    else
+	       ForgetSelection (&e.Selected);
+	    }
+	 if (GetMaxObjectNum (e.obj_type) >= 0 && Select0 && ! e.global)
+	 {
+	    e.highlighted.type = e.obj_type;
+	    e.highlighted.num  = 0;
+	 }
+	 else
+	    e.highlighted.nil ();
+
+	 DragObject = false;
+	 StretchSelBox = false;
+	 RedrawMap = 1;
+	 }
+
+      // [Ctrl][g]: toggle global mode
+      else if (is.key == '\7')
+	 {
+	 static bool dont_warn = false;
+	 bool        ok        = false;
+	 if (e.global)
+	    ok = true;  // No confirmation needed to switch off
+	 else if (dont_warn)
+	    ok = true;
+	 else
+	    {
+	    ok = Confirm (-1, -1,
+			  "Global mode is experimental and probably highly",
+			  "unstable. This means crashes. Are you sure ?");
+	    RedrawMap = 1;
+	    if (ok)
+	       {
+	       dont_warn = true;  // User is sure. Won't ask again
+	       Notify (-1, -1,
+		   "Selection does not work in global mode. Don't",
+		   "bother reporting it, I'm aware of it already.");
+	       }
+	    }
+	 if (ok)
+	    {
+	    ForgetSelection (&e.Selected);
+	    e.global = ! e.global;
+	    RedrawMap = 1;
+	    }
+	 }
+
+      // [e]: Select/unselect all linedefs in non-forked path
+      else if (is.key == 'e' && e.highlighted._is_linedef ())
+	 {
+	 ForgetSelection (&e.Selected);
+	 select_linedefs_path (&e.Selected, e.highlighted.num, YS_ADD);
+	 RedrawMap = 1;
+	 }
+
+      // [Ctrl][e] Select/unselect all linedefs in path
+      else if (is.key == '\5' && ! is.shift && e.highlighted._is_linedef ())
+	 {
+	 select_linedefs_path (&e.Selected, e.highlighted.num, YS_TOGGLE);
+	 RedrawMap = 1;
+	 }
+
+      // [E]: Select/unselect all 1s linedefs in path
+      else if (is.key == 'E' && e.highlighted._is_linedef ())
+	 {
+	 ForgetSelection (&e.Selected);
+	 select_1s_linedefs_path (&e.Selected, e.highlighted.num, YS_ADD);
+	 RedrawMap = 1;
+	 }
+
+      // [Ctrl][Shift][e]: Select/unselect all 1s linedefs in path
+      else if (is.key == '\5' && is.shift && e.highlighted._is_linedef ())
+	 {
+	 select_1s_linedefs_path (&e.Selected, e.highlighted.num, YS_TOGGLE);
+	 RedrawMap = 1;
+	 }
+
+      // [G]: to increase the grid step
+      else if (is.key == 'G')
+	 {
+	 if (e.grid_step < e.grid_step_max)
+	    e.grid_step *= 2;
+	 else
+	    e.grid_step = e.grid_step_min;
+	 RedrawMap = 1;
+	 }
+
+      // [g]: decrease the grid step
+      else if (is.key == 'g')
+	 {
+	 if (e.grid_step > e.grid_step_min)
+	    e.grid_step /= 2;
+	 else
+	    e.grid_step = e.grid_step_max;
+	 RedrawMap = 1;
+	 }
+
+      // [h]: display or hide the grid
+      else if (is.key == 'h')
+	 {
+	 e.grid_shown = ! e.grid_shown;
+	 RedrawMap = 1;
+	 }
+
+      // [H]: reset the grid to grid_step_max
+      else if (is.key == 'H')
+	 {
+	 e.grid_step = e.grid_step_max;
+	 RedrawMap = 1;
+	 }
+
+      // [y]: toggle the snap_to_grid flag
+      else if (is.key == 'y')
+         {
+         e.grid_snap = ! e.grid_snap;
+         }
+
+      // [z]: toggle the lock_grip_step flag
+      else if (is.key == 'z')
+         {
+         e.grid_step_locked = ! e.grid_step_locked;
+         }
+ 
+      // [r]: toggle the rulers
+      else if (is.key == 'r')
+	 e.rulers_shown = !e.rulers_shown;
+
+      // [n], [>]: highlight the next object
+      else if ((is.key == 'n' || is.key == '>')
+	 && (! e.global || e.highlighted ()))
+	 {
+	 obj_type_t t = e.highlighted () ? e.highlighted.type : e.obj_type;
+	 obj_no_t nmax = GetMaxObjectNum (t);
+	 if (is_obj (nmax))
+	    {
+	    if (e.highlighted.is_nil ())
+	       {
+	       e.highlighted.type = t;
+	       e.highlighted.num = 0;
+	       }
+	    else
+	       {
+	       e.highlighted.num++;
+	       if (e.highlighted.num > nmax)
+		  e.highlighted.num = 0;
+	       }
+	    GoToObject (e.highlighted);
+	    RedrawMap = 1;
+	    }
+	 }
+
+      // [p], [<]: highlight the previous object
+      else if ((is.key == 'p' || is.key == '<')
+	 && (! e.global || e.highlighted ()))
+	 {
+	 obj_type_t t = e.highlighted () ? e.highlighted.type : e.obj_type;
+	 obj_no_t nmax = GetMaxObjectNum (t);
+	 if (is_obj (nmax))
+	    {
+	    if (e.highlighted.is_nil ())
+	       {
+	       e.highlighted.type = t;
+	       e.highlighted.num = nmax;
+	       }
+	    else
+	       {
+	       e.highlighted.num--;
+	       if (e.highlighted.num < 0)
+		  e.highlighted.num = nmax;
+	       }
+	    GoToObject (e.highlighted);
+	    RedrawMap = 1;
+	    }
+	 }
+
+      // [j], [#]: jump to object by number
+      else if ((is.key == 'j' || is.key == '#')
+	 && (! e.global || e.highlighted ()))
+	 {
+	 Objid default_obj;
+	 default_obj.type = e.highlighted () ? e.highlighted.type : e.obj_type;
+	 default_obj.num  = e.highlighted () ? e.highlighted.num  : 0;
+	 Objid target_obj;
+	 input_objid (target_obj, default_obj, -1, -1);
+	 if (target_obj ())
+	    GoToObject (target_obj);
+	 RedrawMap = 1;
+	 }
+
+#if 0
+      // [c]: clear selection and redraw the map
+      else if (is.key == 'c')
+	 {
+	 ForgetSelection (&e.Selected);
+	 RedrawMap = 1;
+	 DragObject = false;
+	 StretchSelBox = false;
+	 }
+#endif
+
+      // [o]: copy a group of objects
+      else if (is.key == 'o'
+         && (e.Selected || e.highlighted ()))
+	 {
+         int x, y;
+
+	 /* copy the object(s) */
+	 if (! e.Selected)
+	    SelectObject (&e.Selected, e.highlighted.num);
+	 CopyObjects (e.obj_type, e.Selected);
+	 /* enter drag mode */
+	 //DragObject = true;
+         /* AYM 19980619 : got to look into this!! */
+	 //e.highlight_obj_no = e.Selected->objnum;
+
+         // Find the "hotspot" in the object(s)
+         if (e.highlighted () && ! e.Selected)
+            GetObjectCoords (e.highlighted.type, e.highlighted.num, &x, &y);
+         else
+            centre_of_objects (e.obj_type, e.Selected, &x, &y);
+
+         // Drag the object(s) so that the "hotspot" is under the pointer
+         MoveObjectsToCoords (e.obj_type, 0, x, y, 0);
+         MoveObjectsToCoords (e.obj_type, e.Selected,
+            e.pointer_x, e.pointer_y, 0);
+	 RedrawMap = 1;
+	 StretchSelBox = false;
+	 }
+
+      // [Return]: edit the properties of the current object.
+      else if (is.key == YK_RETURN
+         && (e.Selected || e.highlighted ()))
+	 {
+	 if (e.Selected)
+	    EditObjectsInfo (0, menubar_out_y1 + 1, e.obj_type, e.Selected);
+	 else
+	    {
+	    SelectObject (&e.Selected, e.highlighted.num);
+	    EditObjectsInfo (0, menubar_out_y1 + 1, e.highlighted.type, e.Selected);
+	    UnSelectObject (&e.Selected, e.highlighted.num);
+	    }
+	 RedrawMap = 1;
+	 DragObject = false;
+	 StretchSelBox = false;
+	 }
+
+      // [w]: spin things 1/8 turn counter-clockwise
+      else if (is.key == 'w' && e.obj_type == OBJ_THINGS
+         && (e.Selected || e.highlighted ()))
+	 {
+	 if (! e.Selected)
+	    {
+	    SelectObject (&e.Selected, e.highlighted.num);
+	    spin_things (e.Selected, 45);
+	    UnSelectObject (&e.Selected, e.highlighted.num);
+	    }
+	 else
+	    {
+	    spin_things (e.Selected, 45);
+	    }
+	 RedrawMap = 1;  /* FIXME: should redraw only the things */
+	 DragObject = false;
+	 StretchSelBox = false;
+	 }
+
+      // [w]: split linedefs and sectors
+      else if (is.key == 'w' && e.obj_type == OBJ_LINEDEFS
+         && e.Selected && e.Selected->next && ! e.Selected->next->next)
+         {
+         SplitLineDefsAndSector (e.Selected->next->objnum, e.Selected->objnum);
+         ForgetSelection (&e.Selected);
+         RedrawMap = 1;
+         DragObject = false;
+         StretchSelBox = false;
+         }
+
+      // [x]: spin things 1/8 turn clockwise
+      else if (is.key == 'x' && e.obj_type == OBJ_THINGS
+         && (e.Selected || e.highlighted ()))
+	 {
+	 if (! e.Selected)
+	    {
+	    SelectObject (&e.Selected, e.highlighted.num);
+	    spin_things (e.Selected, -45);
+	    UnSelectObject (&e.Selected, e.highlighted.num);
+	    }
+	 else
+	    {
+	    spin_things (e.Selected, -45);
+	    }
+	 RedrawMap = 1;  /* FIXME: should redraw only the things */
+	 DragObject = false;
+	 StretchSelBox = false;
+	 }
+
+      // [x]: split linedefs
+      else if (is.key == 'x' && e.obj_type == OBJ_LINEDEFS
+         && (e.Selected || e.highlighted ()))
+         {
+         if (! e.Selected)
+            {
+            SelectObject (&e.Selected, e.highlighted.num);
+            SplitLineDefs (e.Selected);
+            UnSelectObject (&e.Selected, e.highlighted.num);
+            }
+         else
+            SplitLineDefs (e.Selected);
+         RedrawMap = 1;
+         DragObject = false;
+         StretchSelBox = false;
+         }
+
+      // [Ctrl][x]: exchange objects numbers
+      else if (is.key == 24)
+	 {
+	 if (! e.Selected
+	     || ! e.Selected->next
+	     || (e.Selected->next)->next)
+	    {
+	    Beep ();
+	    Notify (-1, -1, "You must select exactly two objects", 0);
+	    RedrawMap = 1;
+	    }
+	 else
+	    {
+	    exchange_objects_numbers (e.obj_type, e.Selected, true);
+	    RedrawMap = 1;
+	    }
+	 }
+
+      // [Ctrl][k]: cut a slice out of a sector
+      else if (is.key == 11 && e.obj_type == OBJ_LINEDEFS
+         && e.Selected && e.Selected->next && ! e.Selected->next->next)
+      {
+         sector_slice (e.Selected->next->objnum, e.Selected->objnum);
+         ForgetSelection (&e.Selected);
+         RedrawMap = 1;
+         DragObject = false;
+         StretchSelBox = false;
+      }
+      
+      // [Del]: delete the current object
+      else if (is.key == YK_DEL
+         && (e.Selected || e.highlighted ())) /* 'Del' */
+	 {
+	 if (e.obj_type == OBJ_THINGS
+	  || Expert
+	  || Confirm (-1, -1,
+		(e.Selected && e.Selected->next ?
+		     "Do you really want to delete these objects?"
+		   : "Do you really want to delete this object?"),
+		(e.Selected && e.Selected->next ?
+		     "This will also delete the objects bound to them."
+	           : "This will also delete the objects bound to it.")))
+	    {
+	    if (e.Selected)
+	       DeleteObjects (e.obj_type, &e.Selected);
+	    else
+	       DeleteObject (e.highlighted);
+	    }
+         // AYM 1998-09-20 I thought I'd add this
+         // (though it doesn't fix the problem : if the object has been
+         // deleted, HighlightObject is still called with a bad object#).
+         e.highlighted.nil ();
+	 DragObject = false;
+	 StretchSelBox = false;
+	 RedrawMap = 1;
+	 }
+
+      // [Ins]: insert a new object
+      else if (is.key == YK_INS || is.key == YK_INS + YK_SHIFT) /* 'Ins' */
+	 {
+	 SelPtr cur;
+         int prev_obj_type = e.obj_type;
+
+	 /* first special case: if several vertices are
+	    selected, add new linedefs */
+	 if (e.obj_type == OBJ_VERTICES
+	    && e.Selected && e.Selected->next)
+	    {
+	    int firstv;
+            int obj_no = OBJ_NO_NONE;
+
+	    ObjectsNeeded (OBJ_LINEDEFS, 0);
+	    if (e.Selected->next->next)
+	       firstv = e.Selected->objnum;
+	    else
+	       firstv = -1;
+	    e.obj_type = OBJ_LINEDEFS;
+	    /* create linedefs between the vertices */
+	    for (cur = e.Selected; cur->next; cur = cur->next)
+	       {
+	       /* check if there is already a linedef between the two vertices */
+	       for (obj_no = 0; obj_no < NumLineDefs; obj_no++)
+		  if ((LineDefs[obj_no].start == cur->next->objnum
+		    && LineDefs[obj_no].end   == cur->objnum)
+		   || (LineDefs[obj_no].end   == cur->next->objnum
+		    && LineDefs[obj_no].start == cur->objnum))
+		     break;
+	       if (obj_no < NumLineDefs)
+		  cur->objnum = obj_no;
+	       else
+		  {
+		  InsertObject (OBJ_LINEDEFS, -1, 0, 0);
+		  e.highlighted.type = OBJ_LINEDEFS;
+		  e.highlighted.num  = NumLineDefs - 1;
+		  LineDefs[e.highlighted.num].start = cur->next->objnum;
+		  LineDefs[e.highlighted.num].end = cur->objnum;
+		  cur->objnum = e.highlighted.num;  // FIXME cur = e.highlighted
+		  }
+	       }
+	    /* close the polygon if there are more than 2 vertices */
+	    if (firstv >= 0 && is.shift)
+	       {
+	       e.highlighted.type = OBJ_LINEDEFS;
+	       for (e.highlighted.num = 0;
+                    e.highlighted.num < NumLineDefs;
+                    e.highlighted.num++)
+		  if ((LineDefs[e.highlighted.num].start == firstv
+		    && LineDefs[e.highlighted.num].end   == cur->objnum)
+		   || (LineDefs[e.highlighted.num].end   == firstv
+		    && LineDefs[e.highlighted.num].start == cur->objnum))
+		     break;
+	       if (e.highlighted.num < NumLineDefs)
+		  cur->objnum = obj_no;
+	       else
+		  {
+		  InsertObject (OBJ_LINEDEFS, -1, 0, 0);
+		  e.highlighted.type = OBJ_LINEDEFS;
+		  e.highlighted.num  = NumLineDefs - 1;
+		  LineDefs[e.highlighted.num].start = firstv;
+		  LineDefs[e.highlighted.num].end   = cur->objnum;
+		  cur->objnum = e.highlighted.num;  // FIXME cur = e.highlighted
+		  }
+	       }
+	    else
+	       UnSelectObject (&e.Selected, cur->objnum);
+	    }
+	 /* second special case: if several linedefs are selected,
+	    add new sidedefs and one sector */
+	 else if (e.obj_type == OBJ_LINEDEFS && e.Selected)
+	    {
+	    ObjectsNeeded (OBJ_LINEDEFS, 0);
+	    for (cur = e.Selected; cur; cur = cur->next)
+	       if (LineDefs[cur->objnum].sidedef1 >= 0
+		&& LineDefs[cur->objnum].sidedef2 >= 0)
+		  {
+		  char msg[80];
+
+		  Beep ();
+		  sprintf (msg, "Linedef #%d already has two sidedefs", cur->objnum);
+		  Notify (-1, -1, "Error: cannot add the new sector", msg);
+		  break;
+		  }
+	    if (! cur)
+	       {
+	       e.obj_type = OBJ_SECTORS;
+	       InsertObject (OBJ_SECTORS, -1, 0, 0);
+	       e.highlighted.type = OBJ_SECTORS;
+	       e.highlighted.num  = NumSectors - 1;
+	       for (cur = e.Selected; cur; cur = cur->next)
+		  {
+		  InsertObject (OBJ_SIDEDEFS, -1, 0, 0);
+		  SideDefs[NumSideDefs - 1].sector = e.highlighted.num;
+		  ObjectsNeeded (OBJ_LINEDEFS, OBJ_SIDEDEFS, 0);
+		  if (LineDefs[cur->objnum].sidedef1 >= 0)
+		     {
+		     int s;
+
+		     s = SideDefs[LineDefs[cur->objnum].sidedef1].sector;
+		     if (s >= 0)
+			{
+			Sectors[e.highlighted.num].floorh = Sectors[s].floorh;
+			Sectors[e.highlighted.num].ceilh = Sectors[s].ceilh;
+			strncpy (Sectors[e.highlighted.num].floort,
+			   Sectors[s].floort, WAD_FLAT_NAME);
+			strncpy (Sectors[e.highlighted.num].ceilt,
+			   Sectors[s].ceilt, WAD_FLAT_NAME);
+			Sectors[e.highlighted.num].light = Sectors[s].light;
+			}
+		     LineDefs[cur->objnum].sidedef2 = NumSideDefs - 1;
+		     LineDefs[cur->objnum].flags = 4;
+		     strncpy (SideDefs[NumSideDefs - 1].tex3,
+			 "-", WAD_TEX_NAME);
+		     strncpy (SideDefs[LineDefs[cur->objnum].sidedef1].tex3,
+			 "-", WAD_TEX_NAME);
+		     }
+		  else
+		     LineDefs[cur->objnum].sidedef1 = NumSideDefs - 1;
+		  }
+	       ForgetSelection (&e.Selected);
+	       SelectObject (&e.Selected, e.highlighted.num);
+	       }
+	    }
+	 /* normal case: add a new object of the current type */
+	 else
+	    {
+	    ForgetSelection (&e.Selected);
+	    /* FIXME how do you insert a new object of type T if
+	       no object of that type already exists ? */
+	    obj_type_t t = e.highlighted () ? e.highlighted.type : e.obj_type;
+	    InsertObject (t, e.highlighted.num,
+	       edit_mapx_snapped (&e, e.pointer_x),
+	       edit_mapy_snapped (&e, e.pointer_y));
+	    e.highlighted.type = t;
+	    e.highlighted.num  = GetMaxObjectNum (e.obj_type);
+	    if (e.obj_type == OBJ_LINEDEFS)
+	       {
+	       int v1 = LineDefs[e.highlighted.num].start;
+	       int v2 = LineDefs[e.highlighted.num].end;
+	       if (! Input2VertexNumbers (-1, -1,
+		 "Choose the two vertices for the new linedef", &v1, &v2))
+		  {
+		  DeleteObject (e.highlighted);
+		  e.highlighted.nil ();
+		  }
+	       else
+		  {
+		  LineDefs[e.highlighted.num].start = v1;
+		  LineDefs[e.highlighted.num].end   = v2;
+		  }
+	       }
+	    else if (e.obj_type == OBJ_VERTICES)
+	       {
+	       SelectObject (&e.Selected, e.highlighted.num);
+	       if (AutoMergeVertices (&e.Selected, e.obj_type, 'i'))
+		  RedrawMap = 1;
+	       ForgetSelection (&e.Selected);
+	       }
+	    }
+
+         // Mode-changing code, duplicated from above.
+         // As RQ would say: "I hate to do that". So do I.
+         // The best solution would be to have a mode
+         // changing function that only changes e.obj_type
+         // and emits a "mode change" message. Another part
+         // of the code, responsible for the menus, would
+         // intercept that message and update them. I don't
+         // have the time (as of 1998-12-14) to do it now.
+         if (e.obj_type != prev_obj_type)
+	    {
+	    int new_mode;
+
+	    // What's the number of the new mode ?
+            new_mode = obj_type_to_mode_no (e.obj_type);
+
+	    // Change the flavour of the "Misc" menu.
+	    e.menubar->set_menu (e.mb_ino[MBI_MISC],
+	       e.mb_menu[modes[new_mode].menu_no]);
+	    }
+
+	 DragObject = false;
+	 StretchSelBox = false;
+	 RedrawMap = 1;
+	 }
+
+      // [!] Debug info (not documented)
+      else if (is.key == '!')
+         {
+         DumpSelection (e.Selected);
+         }
+
+      // [@] Show font (not documented)
+      else if (is.key == '@')
+         {
+         show_font ();
+	 RedrawMap = 1;
+         }
+
+      // [|] Show colours (not documented)
+      else if (is.key == '|')
+         {
+         show_colours ();
+	 RedrawMap = 1;
+         }
+
+      // [Ctrl][b] Select linedefs whose sidedefs reference non-existant sectors
+      else if (is.key == 2)
+	 {
+	 bad_sector_number (&e.Selected);
+	 RedrawMap = 1;
+         }
+
+      // [Ctrl][p] Examine game palette (not documented)
+      else if (is.key == 16)
+         {
+	 Palette_viewer pv;
+	 pv.run ();
+	 RedrawMap = 1;
+         }
+
+      // [Ctrl][r] Xref for sidedef (not documented)
+      else if (is.key == 18)
+	 {
+	 xref_sidedef ();
+	 }
+
+      // [Ctrl][s] List secret sectors (not documented)
+      else if (is.key == 19)
+	 {
+	 secret_sectors ();
+	 }
+
+      // [Ctrl][t] List tagged linedefs or sectors
+      else if (is.key == 20)
+	 {
+	 if (e.highlighted._is_sector ())
+	    list_tagged_linedefs (Sectors[e.highlighted.num].tag);
+	 else if (e.highlighted._is_linedef ())
+	    list_tagged_sectors (LineDefs[e.highlighted.num].tag);
+	 else
+	    Beep ();
+	 }
+
+      // [Ctrl][u] Select linedefs with unknown type (not documented)
+      else if (is.key == 21)
+	 {
+	 unknown_linedef_type (&e.Selected);
+	 RedrawMap = 1;
+	 }
+
+      // [Ctrl][v] Toggle between "snap vertex" tool and normal tool
+      // (not documented)
+      else if (is.key == 22)
+	 {
+	 if (e.tool == TOOL_NORMAL)
+	    {
+	    e.tool = TOOL_SNAP_VERTEX;
+	    printf ("Switched to snap vertex tool."
+		  " Press [Ctrl][v] to switch back to normal tool.\n");
+	    }
+	 else
+	    {
+	    e.tool = TOOL_NORMAL;
+	    printf ("Switched back to normal tool.\n");
+	    }
+	 }
+
+      // [&] Show object numbers
+      else if (is.key == '&')
+         {
+         e.show_object_numbers = ! e.show_object_numbers;
+         RedrawMap = 1;
+         }
+
+      // [%] Show things sprites
+      else if (is.key == '%')
+	 {
+	 e.show_things_sprites = ! e.show_things_sprites;
+	 e.show_things_squares = ! e.show_things_sprites;  // Not a typo !
+	 RedrawMap = 1;
+	 }
+
+      /* user likes music */
+      else if (is.key)
+	 {
+	 Beep ();
+	 }
+      }
+
+   /*
+    *	Step 4 -- Misc. cruft
+    */
+
+   done :
+
+   // Auto-scrolling: scroll the map automatically
+   // when the mouse pointer rests near the edge
+   // of the window.
+   // Scrolling is disabled when a pull-down menu
+   // is visible because it would be annoying to see
+   // the map scrolling while you're searching
+   // through the menus.
+
+   if (is.in_window
+      && autoscroll
+      && ! is.scroll_lock
+      && e.menubar->pulled_down () < 0)
+      {
+      unsigned distance;		// In pixels
+
+#define actual_move(total,dist) \
+   ((int) (((total * autoscroll_amp / 100)\
+   * ((double) (autoscroll_edge - dist) / autoscroll_edge))\
+   / Scale))
+
+      distance = is.y;
+      // The reason for the second member of the condition
+      // is that we don't want to scroll when the user is
+      // simply reaching for a menu...
+      if (distance <= autoscroll_edge
+         && e.menubar->is_under_menubar_item (is.x) < 0)
+	 {
+	 if (! UseMouse)
+	    is.y += e.move_speed;
+	 if (MAPY (ScrCenterY) < /*MapMaxY*/ 20000)
+	    {
+	    OrigY += actual_move (ScrMaxY, distance);
+	    RedrawMap = 1;
+	    }
+	 }
+
+      distance = ScrMaxY - is.y;
+      if (distance <= autoscroll_edge)
+	 {
+	 if (! UseMouse)
+	    is.y -= e.move_speed;
+	 if (MAPY (ScrCenterY) > /*MapMinY*/ -20000)
+	    {
+	    OrigY -= actual_move (ScrMaxY, distance);
+	    RedrawMap = 1;
+	    }
+	 }
+
+      distance = is.x;
+      if (distance <= autoscroll_edge)
+	 {
+	 if (! UseMouse)
+	    is.x += e.move_speed;
+	 if (MAPX (ScrCenterX) > /*MapMinX*/ -20000)
+	    {
+	    OrigX -= actual_move (ScrMaxX, distance);
+	    RedrawMap = 1;
+	    }
+	 }
+
+      // The reason for the second member of the condition
+      // is that we don't want to scroll when the user is
+      // simply reaching for the "Help" menu...
+      // Note: the ordinate "3 * FONTH" is of course not
+      // critical. It's just a rough approximation.
+      distance = ScrMaxX - is.x;
+      if (distance <= autoscroll_edge && (unsigned) is.y >= 3 * FONTH)
+	 {
+	 if (! UseMouse)
+	    is.x -= e.move_speed;
+	 if (MAPX (ScrCenterX) < /*MapMaxX*/ 20000)
+	    {
+	    OrigX += actual_move (ScrMaxX, distance);
+	    RedrawMap = 1;
+	    }
+	 }
+      }
+
+   /*
+    *	Step 5 -- Process events that were generated
+    */
+
+   done2:
+
+   // Process events that were generated
+   if (has_event (YE_ZOOM_CHANGED) && ! e.grid_step_locked)
+      {
+      get_event ();
+      edit_grid_adapt (&e);
+      RedrawMap = 1;
+      }
+
+   if (RedrawMap)
+      e.edisplay->need_refresh ();
+   }
+
+delete e.edisplay;
+delete e.selbox;
+delete e.menubar;
+for (size_t n = 0; n < MBM_HELP; n++)
+   delete e.mb_menu[n];
+
+delete menu_linedef_flags;
+delete menu_thing_flags;
+}
+
+
+/*
+ *	zoom_fit - adjust zoom factor to make level fit in window
+ *
+ *	Return 0 on success, non-zero on failure.
+ */
+static int zoom_fit (edit_t& e)
+{
+  // Empty level, 100% will be fine.
+  if (NumVertices == 0)
+    return edit_set_zoom (&e, 1.0);
+
+  update_level_bounds ();
+  double xzoom;
+  if (MapMaxX - MapMinX)
+     xzoom = .95 * ScrMaxX / (MapMaxX - MapMinX);
+  else
+     xzoom = 1;
+  double yzoom;
+  if (MapMaxY - MapMinY)
+     yzoom = .9 * ScrMaxY / (MapMaxY - MapMinY);
+  else
+     yzoom = 1;
+  int r = edit_set_zoom (&e, y_min (xzoom, yzoom));
+  if (r != 0)
+    return 1;
+  CenterMapAroundCoords ((MapMinX + MapMaxX) / 2, (MapMinY + MapMaxY) / 2);
+  return 0;
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/editloop.h	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,12 @@
+/*
+ *	editloop.h
+ *	AYM 1998-09-06
+ */
+
+
+void EditorLoop (const char *); /* SWAP! */
+const char *SelectLevel (int levelno);
+
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/editobj.cc	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,1038 @@
+/*
+ *	editobj.cc
+ *	Object editing routines.
+ *	BW & RQ sometime in 1993 or 1994.
+ */
+
+
+/*
+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 "_edit.h"
+#include "dialog.h"
+#include "editobj.h"
+#include "entry.h"
+#include "flats.h"
+#include "game.h"
+#include "gfx.h"
+#include "levels.h"
+#include "objects.h"
+#include "objid.h"
+#include "oldmenus.h"
+#include "s_slice.h"
+#include "s_swapf.h"
+#include "selectn.h"
+#include "t_spin.h"
+#include "x_mirror.h"
+#include "x_rotate.h"
+
+
+/*
+   ask for an object number and check for maximum valid number
+   (this is just like InputIntegerValue, but with a different prompt)
+*/
+
+int InputObjectNumber (int x0, int y0, int objtype, int curobj)
+{
+int val, key;
+char prompt[80];
+
+HideMousePointer ();
+sprintf (prompt, "Enter a %s number between 0 and %d:",
+   GetObjectTypeName (objtype), GetMaxObjectNum (objtype));
+if (x0 < 0)
+   x0 = (ScrMaxX - 25 - 8 * strlen (prompt)) / 2;
+if (y0 < 0)
+   y0 = (ScrMaxY - 55) / 2;
+DrawScreenBox3D (x0, y0, x0 + 25 + 8 * strlen (prompt), y0 + 55);
+set_colour (WHITE);
+DrawScreenText (x0 + 10, y0 + 8, prompt);
+val = curobj;
+while ((key
+       = InputInteger (x0 + 10, y0 + 28, &val, 0, GetMaxObjectNum (objtype)))
+       != YK_RETURN && key != YK_ESC)
+   Beep ();
+ShowMousePointer ();
+return val;
+}
+
+
+/*
+ *	input_objid - ask for an object number of the specified	type
+ *
+ *	If the user hit [Return], set objid.type to init.type
+ *	and objid.num to whatever number the user entered. If
+ *	the user hit [Esc], call nil() on objid.
+ */
+void input_objid (Objid& objid, const Objid& init, int x0, int y0)
+{
+char prompt[80];
+
+HideMousePointer ();
+sprintf (prompt, "Enter a %s number between 0 and %d:",
+   GetObjectTypeName (init.type), GetMaxObjectNum (init.type));
+if (x0 < 0)
+   x0 = (ScrMaxX - 25 - 8 * strlen (prompt)) / 2;
+if (y0 < 0)
+   y0 = (ScrMaxY - 55) / 2;
+DrawScreenBox3D (x0, y0, x0 + 25 + 8 * strlen (prompt), y0 + 55);
+set_colour (WHITE);
+DrawScreenText (x0 + 10, y0 + 8, prompt);
+int  num = init.num;
+int  key;
+while ((key
+       = InputInteger (x0 + 10, y0 + 28, &num, 0, GetMaxObjectNum (init.type)))
+       != YK_RETURN && key != YK_ESC)
+   Beep ();
+if (key == YK_ESC)
+   objid.nil ();
+else if (key == YK_RETURN)
+   {
+   objid.type = init.type;
+   objid.num  = num;
+   }
+else
+   {
+   nf_bug ("input_objid: bad key %d", (int) key);  // Can't happen
+   objid.nil ();
+   }
+ShowMousePointer ();
+}
+
+
+/*
+   ask for an object number and display a warning message
+*/
+
+int InputObjectXRef (int x0, int y0, int objtype, bool allownone, int curobj)
+{
+const char *const msg1 = "Warning: modifying the cross-references";
+const char *const msg2 = "between some objects may crash the game.";
+char prompt[80];
+size_t maxlen = 0;
+int width;
+int height;
+
+// Dimensions
+sprintf (prompt, "Enter a %s number between 0 and %d%c",
+  GetObjectTypeName (objtype),
+  GetMaxObjectNum (objtype), allownone ? ',' : ':');
+maxlen = 40;				// Why 40 ? -- AYM 2002-04-17
+if (strlen (prompt) > maxlen);
+   maxlen = strlen (prompt);
+if (strlen (msg1) > maxlen)
+   maxlen = strlen (msg1);
+if (strlen (msg2) > maxlen)
+   maxlen = strlen (msg2);
+int ya = 0 + BOX_BORDER + WIDE_VSPACING;
+int yb = ya;
+if (allownone)
+  yb += FONTH;
+int yc = yb + FONTH + WIDE_VSPACING;
+// FIXME should query InputInteger() instead
+int yd = yc + 2 * HOLLOW_BORDER + 2 * NARROW_VSPACING + FONTH + WIDE_VSPACING;
+int ye = yd + FONTH;
+int yf = ye + FONTH + WIDE_VSPACING + BOX_BORDER;
+width  = 2 * BOX_BORDER + 2 * WIDE_HSPACING + maxlen * FONTW;
+height = yf - 0;
+
+// Position
+if (x0 < 0)
+   x0 = (ScrMaxX - width) / 2;
+if (y0 < 0)
+   y0 = (ScrMaxY - height) / 2;
+
+HideMousePointer ();
+DrawScreenBox3D (x0, y0, x0 + width, y0 + height);
+set_colour (WHITE);
+int x = x0 + BOX_BORDER + WIDE_HSPACING;
+DrawScreenText (x, y0 + ya, prompt);
+if (allownone)
+   DrawScreenText (x, y0 + yb, "or -1 for none:");
+set_colour (LIGHTRED);
+DrawScreenText (x, y0 + yd, msg1);
+DrawScreenText (x, y0 + ye, msg2);
+
+int val = curobj;
+int key;
+int min = allownone ? -1 : 0;
+int max = GetMaxObjectNum (objtype);
+while (key = InputInteger (x, y0 + yc, &val, min, max),
+       key != YK_RETURN && key != YK_ESC)
+   Beep ();
+ShowMousePointer ();
+return val;
+}
+
+
+
+/*
+   ask for two vertex numbers and check for maximum valid number
+*/
+
+bool Input2VertexNumbers (int x0, int y0, const char *prompt1, int *v1, int *v2)
+{
+int  key;
+int  maxlen, first;
+char prompt2[80];
+int text_x0;
+int text_y0;
+int entry1_x0;
+int entry1_y0;
+int entry2_x0;
+int entry2_y0;
+// FIXME should let InputInteger() tell us
+const int entry_width  = 2 * HOLLOW_BORDER + 2 * NARROW_HSPACING + 7 * FONTW;
+const int entry_height = 2 * HOLLOW_BORDER + 2 * NARROW_VSPACING + FONTH;
+
+HideMousePointer ();
+sprintf (prompt2, "Enter two numbers between 0 and %d:", NumVertices - 1);
+
+if (strlen (prompt1) > strlen (prompt2))
+   maxlen = strlen (prompt1);
+else
+   maxlen = strlen (prompt2);
+if (x0 < 0)
+   x0 = (ScrMaxX - 25 - 8 * maxlen) / 2;
+if (y0 < 0)
+   y0 = (ScrMaxY - 75) / 2;
+text_x0 = x0 + BOX_BORDER + WIDE_HSPACING;
+text_y0 = y0 + BOX_BORDER + WIDE_VSPACING;
+entry1_x0 = text_x0 + 13 * FONTW;
+entry1_y0 = text_y0 + 3 * FONTH - HOLLOW_BORDER - NARROW_VSPACING;
+entry2_x0 = entry1_x0;
+entry2_y0 = text_y0 + 5 * FONTH - HOLLOW_BORDER - NARROW_VSPACING;
+
+DrawScreenBox3D (x0, y0,
+   x0 + 2 * BOX_BORDER + 2 * WIDE_HSPACING
+      + y_max (entry_width + 13 * FONTW, maxlen * FONTW) - 1,
+   y0 + 2 * BOX_BORDER + 2 * WIDE_VSPACING + 6 * FONTH - 1);
+set_colour (WHITE);
+DrawScreenText (text_x0, text_y0, prompt1);
+set_colour (WINFG);
+DrawScreenText (text_x0, text_y0 + FONTH, prompt2);
+DrawScreenText (text_x0, text_y0 + 3 * FONTH, "Start vertex");
+DrawScreenText (text_x0, text_y0 + 5 * FONTH, "End vertex");
+
+first = 1;
+key = 0;
+for (;;)
+   {
+   DrawScreenBoxHollow (entry1_x0, entry1_y0,
+      entry1_x0 + entry_width - 1, entry1_y0 + entry_height - 1, BLACK);
+   set_colour (first ? WHITE : DARKGREY);
+   DrawScreenText (entry1_x0 + HOLLOW_BORDER + NARROW_HSPACING,
+      entry1_y0 + HOLLOW_BORDER + NARROW_VSPACING, "%d", *v1);
+
+   DrawScreenBoxHollow (entry2_x0, entry2_y0,
+      entry2_x0 + entry_width - 1, entry2_y0 + entry_height - 1, BLACK);
+   set_colour (! first ? WHITE : DARKGREY);
+   DrawScreenText (entry2_x0 + HOLLOW_BORDER + NARROW_HSPACING,
+      entry2_y0 + HOLLOW_BORDER + NARROW_VSPACING, "%d", *v2);
+
+   if (first)
+      key = InputInteger (entry1_x0, entry1_y0, v1, 0, NumVertices - 1);
+   else
+      key = InputInteger (entry2_x0, entry2_y0, v2, 0, NumVertices - 1);
+   if (key==YK_LEFT || key==YK_RIGHT || key==YK_TAB || key==YK_BACKTAB)
+      first = !first;
+   else if (key == YK_ESC)
+      break;
+   else if (key == YK_RETURN)
+      {
+      if (first)
+	 first = 0;
+      else if (*v1 < 0 || *v1 >= NumVertices
+            || *v2 < 0 || *v2 >= NumVertices)
+	 Beep ();
+      else
+	 break;
+      }
+   else
+      Beep ();
+   }
+ShowMousePointer ();
+return (key == YK_RETURN);
+}
+
+
+
+/*
+   edit an object or a group of objects
+*/
+
+void EditObjectsInfo (int x0, int y0, int objtype, SelPtr obj) /* SWAP! */
+{
+char  *menustr[3];
+int    n, val;
+SelPtr cur;
+int    subwin_y0;
+
+ObjectsNeeded (objtype, 0);
+if (! obj)
+   return;
+switch (objtype)
+   {
+   case OBJ_THINGS:
+      ThingProperties (x0, y0, obj);
+      break;
+
+   case OBJ_VERTICES:
+      for (n = 0; n < 3; n++)
+	 menustr[n] = (char *) GetMemory (60);
+      sprintf (menustr[2], "Edit Vertex #%d", obj->objnum);
+      sprintf (menustr[0], "Change X position (Current: %d)",
+         Vertices[obj->objnum].x);
+      sprintf (menustr[1], "Change Y position (Current: %d)",
+         Vertices[obj->objnum].y);
+#ifdef OLDMEN
+      val = DisplayMenuArray (0, y0,
+         menustr[2], 2, NULL, menustr, NULL, NULL, NULL);
+#else
+      val = vDisplayMenu (0, y0, menustr[2],
+         menustr[0], YK_, 0,
+         menustr[1], YK_, 0,
+	 NULL);
+#endif
+      for (n = 0; n < 3; n++)
+	 FreeMemory (menustr[n]);
+      subwin_y0 = y0 + BOX_BORDER + (2 + val) * FONTH;
+      switch (val)
+	 {
+	 case 1:
+	    val = InputIntegerValue (x0 + 42, subwin_y0,
+               y_min (MapMinX, -10000),
+               y_max (MapMaxX, 10000),
+               Vertices[obj->objnum].x);
+	    if (val != IIV_CANCEL)
+	       {
+	       n = val - Vertices[obj->objnum].x;
+	       for (cur = obj; cur; cur = cur->next)
+		  Vertices[cur->objnum].x += n;
+	       MadeChanges = 1;
+	       MadeMapChanges = 1;
+	       }
+	    break;
+
+	 case 2:
+	    val = InputIntegerValue (x0 + 42, subwin_y0,
+               y_min (MapMinY, -10000),
+               y_max (MapMaxY, 10000),
+               Vertices[obj->objnum].y);
+	    if (val != IIV_CANCEL)
+	       {
+	       n = val - Vertices[obj->objnum].y;
+	       for (cur = obj; cur; cur = cur->next)
+		  Vertices[cur->objnum].y += n;
+	       MadeChanges = 1;
+	       MadeMapChanges = 1;
+	       }
+	    break;
+	 }
+      break;
+
+   case OBJ_LINEDEFS:
+      LinedefProperties (x0, y0, obj);
+      break;
+
+   case OBJ_SECTORS:
+      SectorProperties (x0, y0, obj);
+      break;
+   }
+}
+
+
+/*
+   Yuck!  Dirty piece of code...
+*/
+
+bool Input2Numbers (int x0, int y0, const char *name1, const char *name2,
+   int v1max, int v2max, int *v1, int *v2)
+{
+int  key;
+int  maxlen, first;
+bool ok;
+char prompt[80];
+// FIXME copied from InputInteger()...
+int  entry_width  = 2 * HOLLOW_BORDER + 2 * NARROW_HSPACING + 7 * FONTW;
+int  entry_height = 2 * HOLLOW_BORDER + 2 * NARROW_VSPACING + FONTH;
+
+y_snprintf (prompt, sizeof prompt, "Give the %s and %s for the object:",
+   name1, name2);
+maxlen = strlen (prompt);
+
+int title_x0       = BOX_BORDER + FONTW;
+int title_y0       = BOX_BORDER + FONTH / 2;
+int label1_x0      = title_x0;
+int label1_y0      = title_y0 + 2 * FONTH;
+int label2_x0      = title_x0 + (strlen (name1) + 2) * FONTW;
+{
+   int bound = label1_x0 + entry_width + int (FONTW);
+   if (label2_x0 < bound)
+      label2_x0 = bound;
+}
+// FIXME Assuming the range is not longer than the name
+int label2_y0      = label1_y0;
+int entry1_out_x0  = label1_x0;
+int entry1_out_y0  = label1_y0 + 3 * FONTH / 2;
+int entry1_text_x0 = entry1_out_x0 + HOLLOW_BORDER + NARROW_HSPACING;
+int entry1_text_y0 = entry1_out_y0 + HOLLOW_BORDER + NARROW_VSPACING;
+int entry1_out_x1  = entry1_out_x0 + entry_width - 1;
+int entry1_out_y1  = entry1_out_y0 + entry_height - 1;
+int entry2_out_x0  = label2_x0;
+int entry2_out_y0  = label2_y0 + 3 * FONTH / 2;
+int entry2_text_x0 = entry2_out_x0 + HOLLOW_BORDER + NARROW_HSPACING;
+int entry2_text_y0 = entry2_out_y0 + HOLLOW_BORDER + NARROW_VSPACING;
+int entry2_out_x1  = entry2_out_x0 + entry_width - 1;
+int entry2_out_y1  = entry2_out_y0 + entry_height - 1;
+int range1_x0      = entry1_out_x0;
+int range1_y0      = entry1_out_y1 + FONTH / 2;
+int range2_x0      = entry2_out_x0;
+int range2_y0      = entry2_out_y1 + FONTH / 2;
+int window_x1      = entry2_out_x1 + FONTW + BOX_BORDER;
+int window_y1      = range1_y0 + 3 * FONTH / 2 + BOX_BORDER;
+{
+   int bound = 2 * BOX_BORDER + (maxlen + 2) * int (FONTW);
+   if (window_x1 < bound)
+      window_x1 = bound;
+}
+
+if (x0 < 0)
+   x0 = (ScrMaxX - window_x1) / 2;
+if (y0 < 0)
+   y0 = (ScrMaxY - window_y1) / 2;
+
+HideMousePointer ();
+DrawScreenBox3D (x0, y0, x0 + window_x1, y0 + window_y1);
+set_colour     (WHITE);
+DrawScreenText (x0 + title_x0,  y0 + title_x0,  prompt);
+DrawScreenText (x0 + label1_x0, y0 + label1_y0, name1);
+DrawScreenText (x0 + label2_x0, y0 + label2_y0, name2);
+DrawScreenText (x0 + range1_x0, y0 + range1_y0, "(0-%d)", v1max);
+DrawScreenText (x0 + range2_x0, y0 + range2_y0, "(0-%d)", v2max);
+
+first = 1;
+key = 0;
+for (;;)
+   {
+   ok = true;
+   DrawScreenBoxHollow (x0 + entry1_out_x0, y0 + entry1_out_y0,
+      x0 + entry1_out_x1, y0 + entry1_out_y1, BLACK);
+   if (*v1 < 0 || *v1 > v1max)
+      {
+      set_colour (DARKGREY);
+      ok = false;
+      }
+   else
+      set_colour (LIGHTGREY);
+   DrawScreenText (x0 + entry1_text_x0, y0 + entry1_text_y0, "%d", *v1);
+   DrawScreenBoxHollow (x0 + entry2_out_x0, y0 + entry2_out_y0,
+      x0 + entry2_out_x1, y0 + entry2_out_y1, BLACK);
+   if (*v2 < 0 || *v2 > v2max)
+      {
+      set_colour (DARKGREY);
+      ok = false;
+      }
+   else
+      set_colour (LIGHTGREY);
+   DrawScreenText (x0 + entry2_text_x0, y0 + entry2_text_y0, "%d", *v2);
+   if (first)
+      key = InputInteger (x0 + entry1_out_x0, y0 + entry1_out_y0, v1, 0, v1max);
+   else
+      key = InputInteger (x0 + entry2_out_x0, y0 + entry2_out_y0, v2, 0, v2max);
+   if (key==YK_LEFT || key==YK_RIGHT || key==YK_TAB || key==YK_BACKTAB)
+      first = !first;
+   else if (key == YK_ESC)
+      break;
+   else if (key == YK_RETURN)
+      {
+      if (first)
+	 first = 0;
+      else if (ok)
+	 break;
+      else
+	 Beep ();
+      }
+   else
+      Beep ();
+   }
+ShowMousePointer ();
+return (key == YK_RETURN);
+}
+
+
+
+/*
+   insert a standard object at given position
+*/
+
+void InsertStandardObject (int xpos, int ypos, int choice) /* SWAP! */
+{
+int sector;
+int n;
+int a, b;
+
+/* show where the object will be inserted */
+HideMousePointer ();
+DrawPointer (1);
+ShowMousePointer ();
+/* are we inside a Sector? */
+Objid o;
+GetCurObject (o, OBJ_SECTORS, xpos, ypos);
+sector = o.num;
+
+/* !!!! Should also check for overlapping objects (sectors) !!!! */
+switch (choice)
+   {
+   case 1:
+      a = 256;
+      b = 128;
+      if (Input2Numbers (-1, -1, "Width", "Height", 2000, 2000, &a, &b))
+	 {
+	 if (a < 8)
+	    a = 8;
+	 if (b < 8)
+	    b = 8;
+	 xpos = xpos - a / 2;
+	 ypos = ypos - b / 2;
+	 InsertObject (OBJ_VERTICES, -1, xpos, ypos);
+	 InsertObject (OBJ_VERTICES, -1, xpos + a, ypos);
+	 InsertObject (OBJ_VERTICES, -1, xpos + a, ypos + b);
+	 InsertObject (OBJ_VERTICES, -1, xpos, ypos + b);
+	 if (sector < 0)
+	    InsertObject (OBJ_SECTORS, -1, 0, 0);
+	 for (n = 0; n < 4; n++)
+	    {
+	    InsertObject (OBJ_LINEDEFS, -1, 0, 0);
+	    LineDefs[NumLineDefs - 1].sidedef1 = NumSideDefs;
+	    InsertObject (OBJ_SIDEDEFS, -1, 0, 0);
+	    if (sector >= 0)
+	       SideDefs[NumSideDefs - 1].sector = sector;
+	    }
+	 ObjectsNeeded (OBJ_LINEDEFS, 0);
+	 if (sector >= 0)
+	    {
+	    LineDefs[NumLineDefs - 4].start = NumVertices - 4;
+	    LineDefs[NumLineDefs - 4].end = NumVertices - 3;
+	    LineDefs[NumLineDefs - 3].start = NumVertices - 3;
+	    LineDefs[NumLineDefs - 3].end = NumVertices - 2;
+	    LineDefs[NumLineDefs - 2].start = NumVertices - 2;
+	    LineDefs[NumLineDefs - 2].end = NumVertices - 1;
+	    LineDefs[NumLineDefs - 1].start = NumVertices - 1;
+	    LineDefs[NumLineDefs - 1].end = NumVertices - 4;
+	    }
+	 else
+	    {
+	    LineDefs[NumLineDefs - 4].start = NumVertices - 1;
+	    LineDefs[NumLineDefs - 4].end = NumVertices - 2;
+	    LineDefs[NumLineDefs - 3].start = NumVertices - 2;
+	    LineDefs[NumLineDefs - 3].end = NumVertices - 3;
+	    LineDefs[NumLineDefs - 2].start = NumVertices - 3;
+	    LineDefs[NumLineDefs - 2].end = NumVertices - 4;
+	    LineDefs[NumLineDefs - 1].start = NumVertices - 4;
+	    LineDefs[NumLineDefs - 1].end = NumVertices - 1;
+	    }
+	 }
+      break;
+   case 2:
+      a = 8;
+      b = 128;
+      if (Input2Numbers (-1, -1, "Number of sides", "Radius", 32, 2000, &a, &b))
+	 {
+	 if (a < 3)
+	    a = 3;
+	 if (b < 8)
+	    b = 8;
+	 InsertPolygonVertices (xpos, ypos, a, b);
+	 if (sector < 0)
+	    InsertObject (OBJ_SECTORS, -1, 0, 0);
+	 for (n = 0; n < a; n++)
+	    {
+	    InsertObject (OBJ_LINEDEFS, -1, 0, 0);
+	    LineDefs[NumLineDefs - 1].sidedef1 = NumSideDefs;
+	    InsertObject (OBJ_SIDEDEFS, -1, 0, 0);
+	    if (sector >= 0)
+	       SideDefs[NumSideDefs - 1].sector = sector;
+	    }
+	 ObjectsNeeded (OBJ_LINEDEFS, 0);
+	 if (sector >= 0)
+	    {
+	    LineDefs[NumLineDefs - 1].start = NumVertices - 1;
+	    LineDefs[NumLineDefs - 1].end = NumVertices - a;
+	    for (n = 2; n <= a; n++)
+	       {
+	       LineDefs[NumLineDefs - n].start = NumVertices - n;
+	       LineDefs[NumLineDefs - n].end = NumVertices - n + 1;
+	       }
+	    }
+	 else
+	    {
+	    LineDefs[NumLineDefs - 1].start = NumVertices - a;
+	    LineDefs[NumLineDefs - 1].end = NumVertices - 1;
+	    for (n = 2; n <= a; n++)
+	       {
+	       LineDefs[NumLineDefs - n].start = NumVertices - n + 1;
+	       LineDefs[NumLineDefs - n].end = NumVertices - n;
+	       }
+	    }
+	 }
+      break;
+   case 3:
+   /*
+      a = 6;
+      b = 16;
+      if (Input2Numbers (-1, -1, "Number of steps", "Step height", 32, 48, &a, &b))
+	 {
+	 if (a < 2)
+	    a = 2;
+	 ObjectsNeeded (OBJ_SECTORS, 0);
+	 n = Sectors[sector].ceilh;
+	 h = Sectors[sector].floorh;
+	 if (a * b < n - h)
+	    {
+	    Beep ();
+	    Notify (-1, -1, "The stairs are too high for this Sector", 0);
+	    return;
+	    }
+	 xpos = xpos - 32;
+	 ypos = ypos - 32 * a;
+	 for (n = 0; n < a; n++)
+	    {
+	    InsertObject (OBJ_VERTICES, -1, xpos, ypos);
+	    InsertObject (OBJ_VERTICES, -1, xpos + 64, ypos);
+	    InsertObject (OBJ_VERTICES, -1, xpos + 64, ypos + 64);
+	    InsertObject (OBJ_VERTICES, -1, xpos, ypos + 64);
+	    ypos += 64;
+	    InsertObject (OBJ_SECTORS, sector, 0, 0);
+	    h += b;
+	    Sectors[NumSectors - 1].floorh = h;
+
+	    InsertObject (OBJ_LINEDEFS, -1, 0, 0);
+	    LineDefs[NumLineDefs - 1].sidedef1 = NumSideDefs;
+	    LineDefs[NumLineDefs - 1].sidedef2 = NumSideDefs + 1;
+	    InsertObject (OBJ_SIDEDEFS, -1, 0, 0);
+	    SideDefs[NumSideDefs - 1].sector = sector;
+	    InsertObject (OBJ_SIDEDEFS, -1, 0, 0);
+
+	    ObjectsNeeded (OBJ_LINEDEFS, 0);
+	    LineDefs[NumLineDefs - 4].start = NumVertices - 4;
+	    LineDefs[NumLineDefs - 4].end = NumVertices - 3;
+	    LineDefs[NumLineDefs - 3].start = NumVertices - 3;
+	    LineDefs[NumLineDefs - 3].end = NumVertices - 2;
+	    LineDefs[NumLineDefs - 2].start = NumVertices - 2;
+	    LineDefs[NumLineDefs - 2].end = NumVertices - 1;
+	    LineDefs[NumLineDefs - 1].start = NumVertices - 1;
+	    LineDefs[NumLineDefs - 1].end = NumVertices - 4;
+	   }
+	 }
+      break;
+   */
+   case 4:
+      NotImplemented ();
+      break;
+   }
+}
+
+
+
+/*
+   menu of miscellaneous operations
+*/
+
+void MiscOperations (int objtype, SelPtr *list, int val) /* SWAP! */
+{
+char   msg[80];
+int    angle, scale;
+
+if (val > 1 && ! *list)
+   {
+   Beep ();
+   sprintf (msg, "You must select at least one %s", GetObjectTypeName (objtype));
+   Notify (-1, -1, msg, 0);
+   return;
+   }
+
+/* I think this switch statement deserves a prize for "worst
+   gratuitous obfuscation" or something. -- AYM 2000-11-07 */
+switch (val)
+   {
+   case 1:
+      // * -> First free tag number
+      sprintf (msg, "First free tag number: %d", FindFreeTag ());
+      Notify (-1, -1, msg, 0);
+      break;
+
+   case 2:
+      // * -> Rotate and scale
+      if ((objtype == OBJ_THINGS
+         || objtype == OBJ_VERTICES) && ! (*list)->next)
+	 {
+	 Beep ();
+	 sprintf (msg, "You must select more than one %s",
+            GetObjectTypeName (objtype));
+	 Notify (-1, -1, msg, 0);
+	 return;
+	 }
+      angle = 0;
+      scale = 100;
+      if (Input2Numbers (-1, -1, "rotation angle (°)", "scale (%)",
+         360, 1000, &angle, &scale))
+	 RotateAndScaleObjects (objtype, *list, (double) angle * 0.0174533,
+            (double) scale * 0.01);
+      break;
+
+   case 3:
+      // Linedef -> Split
+      if (objtype == OBJ_LINEDEFS)
+	 {
+	 SplitLineDefs (*list);
+	 }
+      // Sector -> Make door from sector
+      else if (objtype == OBJ_SECTORS)
+	 {
+	 if ((*list)->next)
+	    {
+	    Beep ();
+	    Notify (-1, -1, "You must select exactly one sector", 0);
+	    }
+	 else
+	    {
+	    MakeDoorFromSector ((*list)->objnum);
+	    }
+	 }
+      // Thing -> Spin 45° clockwise
+      else if (objtype == OBJ_THINGS)
+	 {
+         spin_things (*list, -45);
+	 }
+      // Vertex -> Delete and join linedefs
+      else if (objtype == OBJ_VERTICES)
+	 {
+	 DeleteVerticesJoinLineDefs (*list);
+	 ForgetSelection (list);
+	 }
+      break;
+
+   case 4:
+      // Linedef -> Split linedefs and sector
+      if (objtype == OBJ_LINEDEFS)
+	 {
+	 if (! (*list)->next || (*list)->next->next)
+	    {
+	    Beep ();
+	    Notify (-1, -1, "You must select exactly two linedefs", 0);
+	    }
+	 else
+	    {
+	    SplitLineDefsAndSector ((*list)->next->objnum, (*list)->objnum);
+	    ForgetSelection (list);
+	    }
+	 }
+      // Sector -> Make lift from sector
+      else if (objtype == OBJ_SECTORS)
+	 {
+	 if ((*list)->next)
+	    {
+	    Beep ();
+	    Notify (-1, -1, "You must select exactly one Sector", 0);
+	    }
+	 else
+	    {
+	    MakeLiftFromSector ((*list)->objnum);
+	    }
+	 }
+      // Thing -> Spin 45° counter-clockwise
+      else if (objtype == OBJ_THINGS)
+         spin_things (*list, 45);
+      // Vertex -> Merge
+      else if (objtype == OBJ_VERTICES)
+	 {
+	 MergeVertices (list);
+	 }
+      break;
+
+   case 5:
+      // Linedef -> Delete linedefs and join sectors
+      if (objtype == OBJ_LINEDEFS)
+	 {
+	 DeleteLineDefsJoinSectors (list);
+	 }
+      // Sector -> Distribute sector floor heights
+      else if (objtype == OBJ_SECTORS)
+	 {
+	 if (! (*list)->next || ! (*list)->next->next)
+	    {
+	    Beep ();
+	    Notify (-1, -1, "You must select three or more sectors", 0);
+	    }
+	 else
+	    {
+	    DistributeSectorFloors (*list);
+	    }
+	 }
+      // Thing -> Mirror horizontally
+      else if (objtype == OBJ_THINGS)
+         {
+	 flip_mirror (*list, OBJ_THINGS, 'm');
+	 }
+      // Vertex -> Add linedef and split sector
+      else if (objtype == OBJ_VERTICES)
+	 {
+	 if (! (*list)->next || (*list)->next->next)
+	    {
+	    Beep ();
+	    Notify (-1, -1, "You must select exactly two vertices", 0);
+	    }
+	 else
+	    {
+	    SplitSector ((*list)->next->objnum, (*list)->objnum);
+	    ForgetSelection (list);
+	    }
+	 }
+      break;
+
+   case 6:
+      // Linedef -> Flip
+      if (objtype == OBJ_LINEDEFS)
+	 {
+	 FlipLineDefs (*list, 1);
+	 }
+      // Sector -> Distribute ceiling heights
+      else if (objtype == OBJ_SECTORS)
+	 {
+	 if (! (*list)->next || ! (*list)->next->next)
+	    {
+	    Beep ();
+	    Notify (-1, -1, "You must select three or more sectors", 0);
+	    }
+	 else
+	    {
+	    DistributeSectorCeilings (*list);
+	    }
+	 }
+      // Things -> Mirror vertically
+      else if (objtype == OBJ_THINGS)
+	 {
+	 flip_mirror (*list, OBJ_THINGS, 'f');
+         }
+      // Vertex -> Mirror horizontally
+      else if (objtype == OBJ_VERTICES)
+	 {
+	 flip_mirror (*list, OBJ_VERTICES, 'm');
+	 }
+      break;
+
+   case 7:
+      // Linedefs -> Swap sidedefs
+      if (objtype == OBJ_LINEDEFS)
+	 {
+	 if (Expert
+            || blindly_swap_sidedefs
+            || Confirm (-1, -1,
+               "Warning: the sector references are also swapped",
+               "You may get strange results if you don't know what you are doing..."))
+	    FlipLineDefs (*list, 0);
+	 }
+      // Sectors -> Raise or lower
+      else if (objtype == OBJ_SECTORS)
+	 {
+	 RaiseOrLowerSectors (*list);
+	 }
+      // Vertices -> Mirror vertically
+      else if (objtype == OBJ_VERTICES)
+	 {
+	 flip_mirror (*list, OBJ_VERTICES, 'f');
+	 }
+      break;
+
+   case 8:
+      // Linedef ->  Align textures vertically
+      if (objtype == OBJ_LINEDEFS)
+	 {
+	 SelPtr sdlist, cur;
+
+	 /* select all sidedefs */
+	 ObjectsNeeded (OBJ_LINEDEFS);
+	 sdlist = 0;
+	 for (cur = *list; cur; cur = cur->next)
+	    {
+	    if (LineDefs[cur->objnum].sidedef1 >= 0)
+	       SelectObject (&sdlist, LineDefs[cur->objnum].sidedef1);
+	    if (LineDefs[cur->objnum].sidedef2 >= 0)
+	       SelectObject (&sdlist, LineDefs[cur->objnum].sidedef2);
+	    }
+	 /* align the textures along the Y axis (height) */
+	 AlignTexturesY (&sdlist);
+	 }
+      // Sector -> Brighten or darken
+      else if (objtype == OBJ_SECTORS)
+	 {
+	 BrightenOrDarkenSectors (*list);
+	 }
+      break;
+
+   case 9:
+      // Linedef -> Align texture horizontally
+      if (objtype == OBJ_LINEDEFS)
+	 {
+	 SelPtr sdlist, cur;
+
+	 /* select all sidedefs */
+	 ObjectsNeeded (OBJ_LINEDEFS,0);
+	 sdlist = 0;
+	 for (cur = *list; cur; cur = cur->next)
+	    {
+	    if (LineDefs[cur->objnum].sidedef1 >= 0)
+	       SelectObject (&sdlist, LineDefs[cur->objnum].sidedef1);
+	    if (LineDefs[cur->objnum].sidedef2 >= 0)
+	       SelectObject (&sdlist, LineDefs[cur->objnum].sidedef2);
+	    }
+	 /* align the textures along the X axis (width) */
+	 AlignTexturesX (&sdlist);
+	 }
+      // Sector -> Unlink room
+      else if (objtype == OBJ_SECTORS)
+	 {
+	 NotImplemented ();  // FIXME
+	 break;
+	 }
+      break;
+
+   case 10:
+      // Linedef -> Make linedef single-sided
+      if (objtype == OBJ_LINEDEFS)
+	 {
+	 SelPtr cur;
+	 ObjectsNeeded (OBJ_LINEDEFS, 0);
+	 for (cur = *list; cur; cur = cur->next)
+	    {
+	    struct LineDef *l = LineDefs + cur->objnum;
+	    l->sidedef2 = -1;  /* remove ref. to 2nd SD */
+	    l->flags &= ~0x04; /* clear "2S" bit */
+	    l->flags |= 0x01;  /* set "Im" bit */
+
+	    if (is_sidedef (l->sidedef1))
+	       {
+	       struct SideDef *s = SideDefs + l->sidedef1;
+	       strcpy (s->tex1, "-");
+	       strcpy (s->tex2, "-");
+	       strcpy (s->tex3, default_middle_texture);
+	       }
+	    /* Don't delete the 2nd sidedef, it could be used
+               by another linedef. And if it isn't, the next
+               cross-references check will delete it anyway. */
+	    }
+	 }
+      // Sector -> Mirror horizontally
+      else if (objtype == OBJ_SECTORS)
+	 {
+	 flip_mirror (*list, OBJ_SECTORS, 'm');
+	 }
+      break;
+
+   case 11:
+      // Linedef -> Make rectangular nook
+      if (objtype == OBJ_LINEDEFS)
+	 MakeRectangularNook (*list, 32, 16, 0);
+      // Sector -> Mirror vertically
+      else if (objtype == OBJ_SECTORS)
+	 {
+	 flip_mirror (*list, OBJ_SECTORS, 'f');
+	 }
+      break;
+
+   case 12:
+      // Linedef -> Make rectangular boss
+      if (objtype == OBJ_LINEDEFS)
+	 MakeRectangularNook (*list, 32, 16, 1);
+      // Sector -> Swap flats
+      else if (objtype == OBJ_SECTORS)
+	 swap_flats (*list);
+      break;
+
+   case 13:
+      // Linedef -> Set length (1st vertex)
+      if (objtype == OBJ_LINEDEFS)
+	 {
+	 static int length = 24;
+	 length = InputIntegerValue (-1, -1, -10000, 10000, length);
+	 if (length != IIV_CANCEL)
+	   SetLinedefLength (*list, length, 0);
+	 }
+      break;
+
+   case 14:
+      // Linedef -> Set length (2nd vertex)
+      if (objtype == OBJ_LINEDEFS)
+	 {
+	 static int length = 24;
+	 length = InputIntegerValue (-1, -1, -10000, 10000, length);
+	 if (length != IIV_CANCEL)
+	   SetLinedefLength (*list, length, 1);
+	 }
+      break;
+
+   case 15:
+      // Linedef -> Unlink 1st sidedef
+      if (objtype == OBJ_LINEDEFS)
+         unlink_sidedef (*list, 1, 0);
+      break;
+
+   case 16:
+      // Linedef -> Unlink 2nd sidedef
+      if (objtype == OBJ_LINEDEFS)
+         unlink_sidedef (*list, 0, 1);
+      break;
+
+   case 17:
+      // Linedef -> Mirror horizontally
+      flip_mirror (*list, OBJ_LINEDEFS, 'm');
+      break;
+      
+   case 18 :
+      // Linedef -> Mirror vertically
+      flip_mirror (*list, OBJ_LINEDEFS, 'f');
+      break;
+
+   case 19 :
+      // Linedef -> Cut a slice out of a sector
+      if (objtype == OBJ_LINEDEFS)
+	 {
+	 if (! (*list)->next || (*list)->next->next)
+	    {
+	    Beep ();
+	    Notify (-1, -1, "You must select exactly two linedefs", 0);
+	    }
+	 else
+	    {
+	    sector_slice ((*list)->next->objnum, (*list)->objnum);
+	    ForgetSelection (list);
+	    }
+	 }
+      break;
+   }
+}
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/editobj.h	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,9 @@
+/*
+ *	editobj.h
+ *	AYM 1998-09-06
+ */
+
+
+void DisplayObjectInfo (const edit_t *e, int); /* SWAP! */
+void input_objid (Objid& objid, const Objid& init, int x0, int y0);
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/editsave.cc	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,273 @@
+/*
+ *	editsave.cc
+ *	Saving an editing session into a pwad
+ *	AYM 1999-04-08
+ */
+
+
+/*
+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 "dialog.h"
+#include "editsave.h"
+#include "entry.h"
+#include "game.h"
+#include "levels.h"
+#include "wadfile.h"
+#include "wadlist.h"
+
+
+#ifndef NEW_SAVE_METHOD
+extern int RedrawMap;
+#endif
+
+
+/*
+ *	save_save_as
+ *	Save the current level into a pwad.
+ *	
+ *	If neither <level_name> nor <file_name> are NULL and the
+ *	level does not come from the iwad and <save_as> is not
+ *	set, there is no interaction at all. The level is saved
+ *	silently into <file_name> as <level_name>.
+ *
+ *	Else, the user is first prompted for a level name and a
+ *	file name (in that order). The level name is given a
+ *	default value of "E1M1" in Doom/Heretic mode or "MAP01"
+ *	in Doom II/Hexen/Strife mode. The file name is given a
+ *	default value of "LEVEL.wad" where LEVEL is the level
+ *	name entered previously, lowercased.  Upon return from
+ *	the function, <level_name> and <file_name> are set
+ *	accordingly.
+ *
+ *	This function is called when the user hits [q], [F2] or
+ *	[F3]. In the latter case, <save_as> is set to true.
+ *
+ *	Note: <level_name> being NULL means that the level name
+ *	is not known, which is the case when using the "c"
+ *	(create) command.  When using the "e" (edit) command,
+ *	the level name is always known, since the level data
+ *	comes from an iwad or pwad. The same goes for
+ *	<file_name>.
+ *
+ *	Upon return from the function, <Level> is updated.
+ *
+ *	FIXME this should be a method of the Editwin class.
+ */
+
+#ifdef NEW_SAVE_METHOD
+bool save_save_as (bool prompt)
+{
+  static char l[WAD_NAME + 1];  // "static" to avoid memory shortages
+  static y_file_name_t f;	// "static" to avoid memory shortages
+ 
+  if (! CheckStartingPos ())
+    return;
+
+  // Fill in the level name
+  if (*Level_name)
+    al_scps (l, Level_name, sizeof l - 1);
+  else
+  {
+    prompt = true;
+    if (yg_level_name == YGLN_MAP01)
+      strcpy (l, "map01");
+    else
+    {
+      strcpy (l, "e1m1");
+      if (yg_level_name != YGLN_E1M1 && yg_level_name != YGLN_E1M10)
+	nf_bug ("Bad yg_level_name %d", (int) yg_level_name);
+    }
+  }
+
+  // Fill in the file name
+  if (*Level_file_name)
+    al_scps (f, file_name, sizeof f - 1);
+  else
+  {
+    prompt = true;
+    al_scpslower (f, l, sizeof f - 1);
+    al_saps (f, ".wad", sizeof f - 1);
+  }
+
+  // Create the dialog
+  Entry2 e ("Save level as...",
+      "Level %*S\nFile %+*s\n", sizeof l - 1, l, sizeof f - 1, f);
+
+try_again :
+
+  // If necessary, prompt for new level name and file name
+  if (prompt || ! fncmp (level_name, MainWad))
+  {
+    int r = e.loop ();
+    if (! r)  // Cancelled by user
+      return false;  // Didn't save
+  }
+
+  printf ("Saving as \"%s\" into \"%s\"\n", l, f);
+  //if (! ok_to_use_weird_level_name (l))
+  //  goto try_again;
+  //if (! ok_to_overwrite (f))
+  //  goto try_again;
+
+  // If file already exists, ask for confirmation.
+  if (al_fnature (l) == 1)
+  {
+    bool ok = Confirm (-1, -1, "This file already exists. Saving to it will"
+	" overwrite _everything_",
+	"else it might contain, including other levels or lumps !");
+    if (! ok)
+    {
+      prompt = true;
+      goto try_again;
+    }
+  }
+
+  // Try to save
+  int r = SaveLevelData (...);
+  if (r)
+  {
+    Notify (-1, -1, "Could not save to file", strerror (errno));
+    prompt = true;
+    goto try_again;
+  }
+
+  // Successfully saved
+  Level = FindMasterDir (levelname);  // FIXME useless ?
+  al_scps (Level_name,            l, sizeof Level_name            - 1);
+  al_scps (Level_file_name,       f, sizeof Level_file_name       - 1);
+  al_scps (Level_file_name_saved, f, sizeof Level_file_name_saved - 1);
+  return true;  // Did save
+}
+#else  /* OLD_SAVE_METHOD */
+
+
+/*
+   get the name of the new wad file (returns NULL on Esc)
+*/
+
+char *GetWadFileName (const char *levelname)
+{
+#define BUFSZ 79
+  char *outfile = (char *) GetMemory (BUFSZ + 1);
+
+  /* get the file name */
+  // If no name, find a default one
+  if (! levelname)
+  {
+    if (yg_level_name == YGLN_E1M1 || yg_level_name == YGLN_E1M10)
+      levelname = "E1M1";
+    else if (yg_level_name == YGLN_MAP01)
+      levelname = "MAP01";
+    else
+    {
+      nf_bug ("Bad ygd_level_name %d, using E1M1.", (int) yg_level_name);
+      levelname = "E1M1";
+    }
+  }
+
+  if (! Level
+    || ! Level->wadfile
+    || ! fncmp (Level->wadfile->filename, MainWad))
+  {
+    al_scpslower (outfile, levelname, BUFSZ);
+    al_saps (outfile, ".wad", BUFSZ);
+  }
+  else
+    strcpy (outfile, Level->wadfile->filename);
+  do
+    InputFileName (-1, -1, "Name of the new wad file:", BUFSZ, outfile);
+  while (! fncmp (outfile, MainWad));
+  /* escape */
+  if (outfile[0] == '\0')
+  {
+    FreeMemory (outfile);
+    return 0;
+  }
+  /* if the wad file already exists, rename it to "*.bak" */
+  Wad_file *wf;
+  for (wad_list.rewind (); wad_list.get (wf);)
+    if (fncmp (outfile, wf->filename) == 0)
+    {
+      verbmsg ("wf->filename: %s\n", wf->filename);	// DEBUG
+      verbmsg ("wf->fp        %p\n", wf->fp);		// DEBUG
+      verbmsg ("outfile       %s\n", outfile);		// DEBUG
+      al_fdrv_t drv;
+      al_fpath_t path;
+      al_fbase_t base;
+
+      al_fana (wf->filename, drv, path, base, 0);
+      sprintf (wf->filename, "%s%s%s.bak", drv, path, base);
+      verbmsg ("setting wf->filename to %s\n", wf->filename);  // DEBUG
+      /* Need to close, then reopen: problems with SHARE.EXE */
+      verbmsg ("closing %p\n", wf->fp);				// DEBUG
+      fclose (wf->fp);
+      verbmsg ("renaming %s -> %s\n", outfile, wf->filename);	// DEBUG
+      if (rename (outfile, wf->filename) != 0)
+      {
+	verbmsg ("removing %s\n", wf->filename);  // DEBUG
+	if (remove (wf->filename) != 0 && errno != ENOENT)
+	{
+	  char buf1[81];
+	  char buf2[81];
+	  y_snprintf (buf1, sizeof buf1, "Could not delete \"%.64s\"",
+	    wf->filename);
+	  y_snprintf (buf2, sizeof buf2, "(%.64s)", strerror (errno));
+	  Notify (-1, -1, buf1, buf2);
+	  return 0;
+	}
+	verbmsg ("renaming %s -> %s\n", outfile, wf->filename);  // DEBUG
+	if (rename (outfile, wf->filename))
+	{
+	  char buf1[81];
+	  char buf2[81];
+	  y_snprintf (buf1, sizeof buf1, "Could not rename \"%.64s\"",
+	    outfile);
+	  y_snprintf (buf2, sizeof buf2, "as \"%.64s\" (%.64s)",
+	    wf->filename, strerror (errno));
+	  Notify (-1, -1, buf1, buf2);
+	  return 0;
+	}
+      }
+      verbmsg ("opening %s\n", wf->filename); // DEBUG
+      wf->fp = fopen (wf->filename, "rb");
+      if (wf->fp == 0)
+      {
+	char buf1[81];
+	char buf2[81];
+	y_snprintf (buf1, sizeof buf1, "Could not reopen \"%.64s\"",
+	  wf->filename);
+	y_snprintf (buf2, sizeof buf2, "(%.64s)", strerror (errno));
+	Notify (-1, -1, buf1, buf2);
+	return 0;
+      }
+      verbmsg ("wf->filename: %s\n", wf->filename);	// DEBUG
+      verbmsg ("wf->fp        %p\n", wf->fp);		// DEBUG
+      verbmsg ("outfile       %s\n", outfile);		// DEBUG
+      break;
+    }
+  return outfile;
+}
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/editsave.h	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,11 @@
+/*
+ *	editsave.h
+ *	AYM 1999-04-11
+ */
+
+
+#ifdef NEW_SAVE_METHOD
+bool save_save_as (bool prompt);
+#endif
+char *GetWadFileName (const char *levelname);
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/editzoom.cc	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,99 @@
+/*
+ *	editzoom.cc
+ *	Zoom functions
+ *	AYM 1998-11-09
+ */
+
+
+/*
+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 <math.h>
+#include "_edit.h"
+#include "editzoom.h"
+#include "events.h"
+#include "gfx.h"
+
+
+double digit_zoom_factors[10];
+
+
+void edit_zoom_init ()
+{
+  double factor = digit_zoom_base / 100.0;
+  double step   = digit_zoom_step != 0 ? (digit_zoom_step + 100.0) / 100
+				       : pow (2, -.5);
+  for (int i = 1; i <= 10; i++, factor *= step)
+    digit_zoom_factors[i % 10] = factor;
+}
+
+
+int edit_zoom_in (edit_t *e)
+{
+  if (! e) return 1;  // Prevent compiler warning about unused .p.
+  double step = zoom_step != 0 ? (zoom_step + 100.0) / 100 : sqrt (2);
+  if (Scale * step > 10.0)
+    return 1;
+  OrigX += (int) ((is.x - ScrCenterX) / Scale);
+  OrigY += (int) ((ScrCenterY - is.y) / Scale);
+  Scale *= step;
+  OrigX -= (int) ((is.x - ScrCenterX) / Scale);
+  OrigY -= (int) ((ScrCenterY - is.y) / Scale);
+  send_event (YE_ZOOM_CHANGED);
+  return 0;
+}
+
+
+int edit_zoom_out (edit_t *e)
+{
+  if (! e) return 1;  // Prevent compiler warning about unused .p.
+  double step = zoom_step != 0 ? (zoom_step + 100.0) / 100 : sqrt (2);
+  if (Scale / step < 0.05)
+    return 1;
+  OrigX += (int) ((is.x - ScrCenterX) / Scale);
+  OrigY += (int) ((ScrCenterY - is.y) / Scale);
+  Scale /= step;
+  OrigX -= (int) ((is.x - ScrCenterX) / Scale);
+  OrigY -= (int) ((ScrCenterY - is.y) / Scale);
+  send_event (YE_ZOOM_CHANGED);
+  return 0;
+}
+
+
+int edit_set_zoom (edit_t *e, double zoom_factor)
+{
+  if (! e) return 1;  // Prevent compiler warning about unused .p.
+  if (zoom_factor < 0.05)
+    zoom_factor = 0.05;
+  if (zoom_factor > 10.0)
+    zoom_factor = 10.0;
+  OrigX += (int) ((is.x - ScrCenterX) / Scale);
+  OrigY += (int) ((ScrCenterY - is.y) / Scale);
+  Scale = zoom_factor;
+  OrigX -= (int) ((is.x - ScrCenterX) / Scale);
+  OrigY -= (int) ((ScrCenterY - is.y) / Scale);
+  send_event (YE_ZOOM_CHANGED);
+  return 0;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/editzoom.h	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,50 @@
+/*
+ *	editzoom.h
+ *	AYM 1998-11-09
+ */
+
+
+/* zoom factors for the digit keys
+ */
+extern double digit_zoom_factors[10];
+
+
+/*
+ *      edit_zoom_init - initialise
+ */
+void edit_zoom_init (void);
+
+
+/*
+ *	edit_zoom_in - zoom_in
+ *
+ *	If zooming in would result in a zoom factor higher than
+ *	10.0, do nothing.
+ *
+ *	Return 0 on success, non-zero on failure.
+ */
+int edit_zoom_in (edit_t *e);
+
+
+/*
+ *	edit_zoom_out - zoom_out
+ *
+ *	If zooming out would result in a zoom factor lesser than
+ *	0.05, do nothing.
+ *
+ *	Return 0 on success, non-zero on failure.
+ */
+int edit_zoom_out (edit_t *e);
+
+
+/*
+ *	edit_set_zoom - set zoom factor
+ *
+ *	If the new zoom factor is less than 0.05 or more than
+ *	10.0, do nothing.
+ *
+ *	Return 0 on success, non-zero on failure.
+ */
+int edit_set_zoom (edit_t *e, double zoom_factor);
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/edwidget.h	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,34 @@
+/*
+ *	edwidget.h
+ *	The class edwidget_c from which the edisplay widget are derived.
+ *	AYM 1998-09-23
+ */
+
+
+#ifndef YH_EDWIDGET  /* DO NOT INSERT ANYTHING BEFORE THIS LINE */
+#define YH_EDWIDGET
+
+
+class edwidget_c
+   {
+   public :
+      void const unset         ();
+      void const draw          ();	// Draw yourself
+      void const undraw        ();	// If you're drawn, undraw yourself
+      int  const can_undraw    ();	// Can you undraw yourself ?
+      int  const need_to_clear ();	// You need to undraw yself but can't ?
+      void const clear         ();	// Forget you're drawn
+      int  const req_width     ();	// Tell me the width you'd like to have
+      int  const req_height    ();	// Tell me the height you'd like 2 have
+      void const set_x0        (int x0);// This is your top left corner
+      void const set_y0        (int y0);
+      void const set_x1        (int x1);// This is your bottom right corner
+      void const set_y1        (int y1);
+      int  const get_x0        ();	// Tell me where's your top left corner
+      int  const get_y0        ();
+      int  const get_x1        ();	// Tell me where's your bottom right c.
+      int  const get_y1        ();
+   };
+
+
+#endif  /* DO NOT ADD ANYTHING AFTER THIS LINE */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/endian.cc	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,66 @@
+/*
+ *	endian.cc
+ *	Determine the native endianness
+ *	AYM 1999-03-30
+ */
+
+
+/*
+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 "endian.h"
+
+
+/*
+ *	Returns 0 for little-endian, 1 for big-endian
+ */
+int native_endianness ()
+{
+verbmsg ("CPU endianness: ");
+union
+   {
+   char mem[17];  // 5 is enough in theory
+   u32 n;
+   } u;
+memset (u.mem, '\0', sizeof (u.mem));
+u.n = 0x31323334;
+if (! strcmp (u.mem, "1234"))
+   {
+   verbmsg ("big-endian\n");
+   return 1;
+   }
+else if (! strcmp (u.mem, "4321"))
+   {
+   verbmsg ("little-endian\n");
+   return 0;
+   }
+else
+   {
+   verbmsg ("unknown\n");
+   warn ("weird endianness \"%s\". Report this to the maintainer!\n", u.mem);
+   return 0;
+   }
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/endian.h	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,10 @@
+/*
+ *	endian.h
+ *	Determine native endianness
+ *	AYM 1999-03-30
+ */
+
+
+int native_endianness ();  // Returns 0 for little-endian, 1 for big-endian
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/entry.cc	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,328 @@
+/*
+ *	entry.cc
+ *	Entry "widgets" (ahem).
+ *	AYM 1998-11-30
+ */
+
+
+/*
+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 "entry.h"
+#include "gfx.h"
+
+
+const char *strgetl (const char *& str, long& value);
+
+
+/*
+ *	InputInteger - display the integer input box
+ *
+ *	FIXME *valp, minv and maxv should be changed to long.
+ */
+int InputInteger (int x0, int y0, int *valp, int minv, int maxv)
+{
+  int key;
+  int entry_out_x0;
+  int entry_out_y0;
+  int entry_out_x1;
+  int entry_out_y1;
+  int entry_text_x0;
+  int entry_text_y0;
+  int entry_text_x1;
+  int entry_text_y1;
+  const size_t boxlen    = 7;    // Visible width of entry box
+  const size_t bufmaxlen = 50;     // Slack enough
+  char *buf = new char[bufmaxlen + 1];
+
+  entry_out_x0  = x0;
+  entry_text_x0 = entry_out_x0 + HOLLOW_BORDER + NARROW_HSPACING;
+  entry_text_x1 = entry_text_x0 + boxlen * FONTW - 1;
+  entry_out_x1  = entry_text_x1 + HOLLOW_BORDER + NARROW_HSPACING;
+  entry_out_y0  = y0;
+  entry_text_y0 = entry_out_y0 + HOLLOW_BORDER + NARROW_VSPACING;
+  entry_text_y1 = entry_text_y0 + FONTH - 1;
+  entry_out_y1  = entry_text_y1 + HOLLOW_BORDER + NARROW_VSPACING;
+  DrawScreenBoxHollow (entry_out_x0, entry_out_y0, entry_out_x1, entry_out_y1,
+    BLACK);
+  long val = *valp;
+  sprintf (buf, "%d", *valp);    // FIXME what if we were in hex ?
+  for (bool firstkey = true; ; firstkey = false)
+  {
+    bool ok;
+    {
+      const char *checkp = buf;
+      ok = strgetl (checkp, val) == 0
+        && checkp == buf + strlen (buf)
+	&& val >= minv && val <= maxv;
+    }
+    set_colour (BLACK);
+    DrawScreenBox (entry_text_x0, entry_text_y0, entry_text_x1, entry_text_y1);
+    if (ok)
+      set_colour (WHITE);
+    else
+      set_colour (LIGHTRED);
+    if (strlen (buf) > boxlen)
+    {
+      DrawScreenText (entry_text_x0, entry_text_y0, "<%s",
+	buf + (strlen (buf) - boxlen + 1));
+    }
+    else
+      DrawScreenString (entry_text_x0, entry_text_y0, buf);
+
+    key = get_key ();
+    if (key == YK_BACKSPACE && strlen (buf) > 0)
+    {
+      buf[strlen (buf) - 1] = '\0';
+    }
+    else if (key == YK_RETURN && ok)
+    {
+      *valp = (int) val;
+      break;    // Return current value
+    }
+    else if (key == YK_LEFT || key == YK_RIGHT
+	  || key == YK_UP   || key == YK_DOWN
+	  || key == YK_TAB  || key == YK_BACKTAB)
+    {
+      *valp = (int) val;
+      break;    // Return current value, even if not valid
+    }
+    else if (key == YK_ESC)
+    {
+      *valp = IIV_CANCEL;    // Return an out of range value
+      break;
+    }
+    else if (is_ordinary (key) && strlen (buf) < bufmaxlen)
+    {
+      if (firstkey)
+	if (key == ' ')    // Kludge : hit space to append to initial value
+	  continue;
+	else
+	  *buf = '\0';
+      al_sapc (buf, key, bufmaxlen);
+    }
+    else
+    {
+      Beep ();
+    }
+  }
+
+  is.key = 0;    // Shouldn't have to do that but EditorLoop() is broken
+  delete[] buf;
+  return key;
+}
+
+
+/*
+   ask for an integer value and check for minimum and maximum
+*/
+int InputIntegerValue (int x0, int y0, int minv, int maxv, int defv)
+{
+  int  val, key;
+  char prompt[80];
+
+  HideMousePointer ();
+  y_snprintf (prompt, sizeof prompt,
+    "Enter a number between %d and %d:",
+    minv, maxv);
+  if (x0 < 0)
+    x0 = (ScrMaxX - 25 - FONTW * strlen (prompt)) / 2;
+  if (y0 < 0)
+    y0 = (ScrMaxY - 55) / 2;
+  DrawScreenBox3D (x0, y0, x0 + 25 + FONTW * strlen (prompt), y0 + 55);
+  set_colour (WHITE);
+  DrawScreenText (x0 + 10, y0 + 8, prompt);
+  val = defv;
+  while ((key = InputInteger (x0 + 10, y0 + 28, &val, minv, maxv)) != YK_RETURN
+   && key != YK_ESC)
+    Beep ();
+  ShowMousePointer ();
+  return val;
+}
+
+
+/*
+   ask for a filename
+*/
+void InputFileName (int x0, int y0, const char *prompt, size_t maxlen,
+   char *filename)
+{
+  int   key;
+  size_t l;
+  size_t boxlen;
+  bool  firstkey;
+  int width;
+  int title_y0;
+  int entry_out_x0;
+  int entry_out_y0;
+  int entry_out_x1;
+  int entry_out_y1;
+  int entry_text_x0;
+  int entry_text_y0;
+  int entry_text_x1;
+  int entry_text_y1;
+
+  HideMousePointer ();
+  for (l = strlen (filename) + 1; l <= maxlen; l++)
+    filename [l] = '\0';
+  /* compute the width of the input box */
+  if (maxlen > 20)
+    boxlen = 20;
+  else
+    boxlen = maxlen;
+  /* compute the width of the dialog box */
+  if (strlen (prompt) > boxlen)
+    l = strlen (prompt);
+  else
+    l = boxlen;
+
+  width = 2 * HOLLOW_BORDER + 2 * NARROW_HSPACING + boxlen * FONTW;
+  if ((int) (strlen (prompt) * FONTW) > width)
+    width = strlen (prompt) * FONTW;
+  width += 2 * BOX_BORDER + 2 * WIDE_HSPACING;
+
+  if (x0 < 0)
+    x0 = (ScrMaxX - width) / 2;
+  if (y0 < 0)
+    y0 = (ScrMaxY - 2 * BOX_BORDER
+		  - 2 * WIDE_VSPACING
+		  - (int) (2.5 * FONTH)
+		  - 2 * HOLLOW_BORDER
+		  - 2 * NARROW_VSPACING) / 2;
+  /* draw the dialog box */
+  entry_out_x0  = x0 + BOX_BORDER + WIDE_HSPACING;
+  entry_text_x0 = entry_out_x0  + HOLLOW_BORDER + NARROW_HSPACING;
+  entry_text_x1 = entry_text_x0 + boxlen * FONTW - 1;
+  entry_out_x1  = entry_text_x1 + NARROW_HSPACING + HOLLOW_BORDER;
+  title_y0      = y0 + BOX_BORDER + WIDE_VSPACING;
+  entry_out_y0  = title_y0 + (int) (1.5 * FONTH);
+  entry_text_y0 = entry_out_y0  + HOLLOW_BORDER + NARROW_VSPACING;
+  entry_text_y1 = entry_text_y0 + FONTH - 1;
+  entry_out_y1  = entry_text_y1 + NARROW_VSPACING + HOLLOW_BORDER;
+
+  DrawScreenBox3D (x0, y0, x0 + width - 1, entry_out_y1 + WIDE_VSPACING);
+  DrawScreenBoxHollow (entry_out_x0, entry_out_y0, entry_out_x1, entry_out_y1, BLACK);
+  set_colour (WINTITLE);
+  DrawScreenString (entry_out_x0, title_y0, prompt);
+  firstkey = true;
+  for (;;)
+  {
+    l = strlen (filename);
+    set_colour (BLACK);
+    DrawScreenBox (entry_text_x0, entry_text_y0, entry_text_x1, entry_text_y1);
+    set_colour (WHITE);
+    if (l > boxlen)
+    {
+      DrawScreenText (entry_text_x0, entry_text_y0, "<%s",
+	filename + (l - boxlen + 1));
+    }
+    else
+      DrawScreenString (entry_text_x0, entry_text_y0, filename);
+    key = get_key ();
+    if (firstkey && is_ordinary (key))
+    {
+      for (l = 0; l <= maxlen; l++)
+	filename[l] = '\0';
+      l = 0;
+    }
+    firstkey = false;
+    if (l < maxlen && is_ordinary (key))
+    {
+      filename[l] = key;
+      filename[l + 1] = '\0';
+    }
+    else if (l > 0 && key == YK_BACKSPACE)
+      filename[l-1] = '\0';
+    else if (key == YK_RETURN)
+      break;  /* return "filename" */
+    else if (key == YK_ESC)
+    {
+      filename[0] = '\0'; /* return an empty string */
+      break;
+    }
+    else
+      Beep ();
+  }
+  ShowMousePointer ();
+  is.key = 0;  // Shouldn't have to do that but EditorLoop() is broken
+}
+
+
+/*
+ *      strgetl - parse a C-style signed long integer
+ *
+ *	Parse anything that would be a legal C signed long
+ *	integer literal (L and U suffixes are not allowed).
+ *	After the function returns, <str> points on the first
+ *	character that could not be parsed. If what was parsed
+ *	constitutes a valid integer, <value> contains its value
+ *	and the return value is a null pointer. Otherwise,
+ *	<value> is undefined and the return value is a static
+ *	string describing the error.
+ */
+const char *strgetl (const char *& str, long& value)
+{
+  int base = 10;
+  int sign = 1;
+
+  // Leading + or -
+  if (*str == '-')
+  {
+    sign = -1;
+    str++;
+  }
+  else if (*str == '+')
+    str++;
+
+  // 0- or 0x- prefix
+  if (*str == '0' && (str[1] == 'x' || str[1] == 'X'))
+  {
+    base = 16;
+    str += 2;
+  }
+  else if (*str == '0')
+    base = 8;    // Don't advance str, so that "0" passes the next test
+
+  // Check that there is at least one digit
+  if (hextoi (*str) < 0 || hextoi (*str) >= base)
+  {
+    if (base == 8)
+      return "expected an octal digit";
+    else if (base == 10)
+      return "expected a decimal digit";
+    else
+      return "expected a hex digit";
+  }
+
+  // Swallow all non-prefix digits
+  for (value = 0; *str != '\0'; str++)
+  {
+    int digitval = hextoi (*str);
+    if (digitval < 0 || digitval >= base)
+      return 0;
+    value = base * value + sign * digitval;
+  }
+  return 0;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/entry.h	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,12 @@
+/*
+ *	entry.h
+ *	Entry "widgets".
+ *	AYM 1998-11-30
+ */
+
+
+int InputInteger (int, int, int *, int, int);
+int InputIntegerValue (int, int, int, int, int);
+void InputFileName (int, int, const char *, size_t, char *);
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/entry2.cc	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,725 @@
+/*
+ *	entry2.cc
+ *	A string entry box class
+ *	AYM 1999-04-12
+ */
+
+
+/*
+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 "entry2.h"
+#include "gfx.h"
+
+
+/*
+ *	ctor
+ */
+Entry2::Entry2 (const char *title, const char *fmt, ...)
+{
+  this->title = title ? title : "(null)";
+  nfields = count_widgets (fmt);
+  box_len     = new unsigned short[nfields];
+  buf         = new char *[nfields];
+  buf_max_len = new unsigned short[nfields];
+  caption     = new const char *[nfields];
+  entry_drawn = new bool[nfields];
+  entry_flags = new _field_flags_t[nfields];
+
+  {
+    va_list args;
+    va_start (args, fmt);
+    fill_in_widgets_info (fmt, args);
+  }
+
+  background_drawn = false;
+  for (size_t f = 0; f < nfields; f++)
+    entry_drawn[f] = false;
+  field_no = 0;  // This seem redundant with jump_to_field (0)
+  		 // but it's not. jump_to_field() really needs
+		 // field_no to be initialized.
+  jump_to_field (0);
+  geom_up_to_date = false;
+  win_x0 = -1;
+  win_y0 = -1;
+
+  // Geometry constants
+  entry_hofs     = HOLLOW_BORDER + NARROW_HSPACING;
+  entry_vofs     = HOLLOW_BORDER + NARROW_VSPACING;
+  win_hofs       = BOX_BORDER + WIDE_HSPACING;
+  win_vofs       = BOX_BORDER + WIDE_VSPACING;
+  title_vspacing = FONTH;
+}
+
+
+/*
+ *	dtor
+ */
+Entry2::~Entry2 ()
+{
+  if (buf)
+    delete[] buf;
+  if (buf_max_len)
+    delete[] buf_max_len;
+  if (box_len)
+    delete[] box_len;
+  if (entry_drawn)
+    delete[] entry_drawn;
+  if (entry_flags)
+    delete[] entry_flags;
+  if (caption)
+    delete[] caption;
+}
+
+ 
+/*
+ *	loop
+ *	Block until the user closes the window.
+ *	Return 0 on cancel, non-zero on valid.
+ */
+int Entry2::loop ()
+{
+  HideMousePointer ();
+  int r;
+  for (;;)
+  {
+    get_input_status ();
+    r = process_event (is);
+    refresh ();
+    if (r != ACT_NONE)
+      break;
+  }
+  is.key = 0;  // FIXME Shouldn't have to do that but EditorLoop() is broken
+  if (r == ACT_VALID)
+    return 1;
+  else if (r == ACT_CANCEL)
+    return 0;
+  else
+  {
+    printf ("Internal error: Entry2::process_event returned %d\n", (int) r);
+    return 0;
+  }
+  ShowMousePointer ();
+}
+
+
+/*
+ *	process_event
+ */
+Entry2_action_t Entry2::process_event (const input_status_t &is)
+{
+  if (is.key == YE_EXPOSE)
+  {
+    background_drawn = false;
+    return ACT_NONE;
+  }
+
+  char *s = buf[field_no];
+  bool redraw = false;
+  size_t max_len = buf_max_len[field_no];
+  size_t l = strlen (s);
+  int key = is.key;
+  _field_flags_t flags = entry_flags[field_no];
+
+  if (first_key && is_ordinary (key))
+  {
+    *s = '\0';
+    l = 0;
+    redraw = true;
+  }
+  first_key = 0;
+
+  // Printable character
+  if (is_ordinary (key))
+  {
+    if (l >= max_len)
+      goto reject_key;
+    if (is_integer_entry (flags))
+    {
+      if (l == 1 && s[0] == '0')
+      {
+	if (key == 'x' || key == 'X')
+	  ;
+	else if (! isdigit (key))
+	  goto reject_key;
+        else if (key == '0')
+	  goto reject_key;
+	else
+	  l = 0;
+      }
+      else if (! isdigit (key))
+	goto reject_key;
+    }
+    if (is_string_entry (flags) && (flags & FF_UPPERCASE))
+      key = toupper (key);
+    s[l] = key;
+    s[l + 1] = '\0';
+    redraw = true;
+  }
+  // [BS]: Backspace
+  else if (key == YK_BACKSPACE)
+  {
+    if (is_integer_entry (flags) && l == 1)
+      strcpy (s, "0");
+    else if (l > 0)
+      s[l-1] = '\0';
+    else
+      goto reject_key;
+    redraw = true;
+  }
+  // ^A, [Home]: Go to SOL (Emacs/readline, Doskey)
+  else if (key == YK_HOME || key == 1)
+  {
+    ;
+  }
+  // ^B, [Left]: Go to previous character (Emacs, readline)
+  else if (key == YK_LEFT || key == 2)
+  {
+    ;
+  }
+  // ^D, [Del]: Delete current character (Emacs, readline)
+  else if (key == YK_DEL || key == 4)
+  {
+    ;
+  }
+  // ^E, [End]: Go to EOL (Emacs/readline, Doskey)
+  else if (key == YK_END || key == 5)
+  {
+    ;
+  }
+  // ^F, [Right]: Go to next character (Emacs/readline)
+  else if (key == YK_RIGHT || key == 6)
+  {
+    ;
+  }
+  // ^K, [Ctrl][End]: Del to EOL (Emacs/readline, Doskey)
+  else if (key == YK_END + YK_CTRL || key == 11)
+  {
+    ;
+  }
+  // ^U, [Ctrl][Home]: Del to SOL (readline, Doskey)
+  else if (key == YK_HOME + YK_CTRL || key == 21)
+  {
+    if ((flags & FF_SUBTYPE) == FF_INTEGER)
+      strcpy (s, "0");
+    else
+      *s = '\0';
+    redraw = true;
+  }
+  // ^W: Del last word (Unix, readline)
+  else if (key == 23)
+  {
+    while (l > 0 && isspace (s[l - 1]))
+      l--;
+    while (l > 0 && ! isspace (s[l - 1]))
+      l--;
+    if (is_integer_entry (flags) && l == 0)
+      strcpy (s, "0");
+    else
+      s[l] = '\0';
+    redraw = true;
+  }
+  // ^X: Decrement (Vim)
+  else if (key == 24)
+  {
+    if (! is_integer_entry (flags))
+      goto reject_key;
+    //v--;
+    //sprintf (s, "%", v);
+  }
+  // [Tab]: Next field
+  else if (key == YK_TAB)
+    next_field ();
+  // [Shift][Tab]: Previous field
+  else if (key == YK_BACKTAB)
+    prev_field ();
+  // [Return]: Validate
+  else if (key == YK_RETURN)
+  {
+    size_t f;
+    for (f = 0; f < nfields; f++)  // No FF_NONEMPTY fields must be empty
+      if (   (entry_flags[f] & FF_TYPE) == FF_ENTRY
+	  && (entry_flags[f] & FF_SUBTYPE) == FF_STRING
+	  && (entry_flags[f] & FF_NONEMPTY)
+	  && buf[f][0] == '\0')
+	break;
+    if (f == nfields)
+      return ACT_VALID;
+    else
+    {
+      jump_to_field (f);
+      Beep ();
+    }
+  }
+  // [Esc]: Cancel
+  else if (key == YK_ESC)
+    return ACT_CANCEL;
+  else
+  {
+reject_key :
+    Beep ();
+  }
+
+  if (redraw)
+    entry_drawn[field_no] = false;
+  return ACT_NONE;
+}
+
+
+/*
+ *	refresh
+ *	Update the display
+ */
+void Entry2::refresh ()
+{
+  /* Draw the background (the part that never
+     changes unless the window is obscured). */
+  if (! background_drawn)
+  {
+    if (! geom_up_to_date)
+      do_geom ();
+
+    DrawScreenBox3D (win_x0, win_y0, win_x1, win_y1);
+    push_colour (WINTITLE);
+    DrawScreenString (title_x0, title_y0, title);
+    set_colour (WINFG);
+    for (size_t f = 0; f < nfields; f++)
+    {
+      size_t yofs = f * vstep;
+      DrawScreenString (caption_x0, caption_y0 + yofs, caption[f]);
+      DrawScreenBoxHollow (entry_box_x0,
+			   entry_box_y0 + yofs,
+	  		   entry_box_x0 + box_len[f] * FONTW + 2*entry_hofs - 1,
+			   entry_box_y1 + yofs,
+			   BLACK);
+    }
+    pop_colour ();
+  }
+
+  /* Draw the foreground (the part that might
+     change as a result of the user actions). */
+  for (size_t f = 0; f < nfields; f++)
+  {
+    if (! background_drawn || ! entry_drawn[f])
+    {
+      size_t l = strlen (buf[f]);
+      int yofs = f * vstep;
+      set_colour (BLACK);
+      DrawScreenBox (entry_text_x0,
+		     entry_text_y0 + yofs,
+		     entry_text_x0 + box_len[f] * FONTW - 1,
+		     entry_text_y1 + yofs);
+      set_colour (WINFG);
+      if (l >= box_len[f])
+      {
+	DrawScreenText (entry_text_x0, entry_text_y0 + yofs, "<%s",
+	  buf[f] + l - (box_len[f] - 2));
+      }
+      else
+	 DrawScreenString (entry_text_x0, entry_text_y0 + yofs, buf[f]);
+      if (f != field_no)
+        entry_drawn[f] = true;
+    }
+  }
+
+  // Draw the cursor
+  if (! background_drawn || ! entry_drawn[field_no])
+  {
+    push_colour (WINFG);
+    int cur_pos = strlen (buf[field_no]);
+    if (cur_pos >= box_len[field_no])
+      cur_pos = box_len[field_no] - 1;
+    int x = entry_text_x0 + cur_pos * FONTW;
+    int y = entry_text_y0 + field_no * vstep;
+    DrawScreenBoxwh (x, y, FONTW, FONTH);
+    pop_colour ();
+    entry_drawn[field_no] = true;
+  }
+
+  background_drawn = true;
+}
+
+
+/*
+ *	PRIVATE METHODS
+ */
+
+
+/*
+ *	count_widget
+ *	Return the number of widgets found in <fmt>.
+ */
+int Entry2::count_widgets (const char *fmt)
+{
+  int nwidgets = 0;
+  for (const char *p = fmt; *p; p++)
+  {
+    if (p[0] == '%' && p[1] != '%')
+      nwidgets++;
+  }
+  return nwidgets;
+}
+
+
+/*
+ *	fill_in_widgets_info
+ *	Parse <fmt> and fill in the widgets info arrays.
+ *	Return 0 on success, non-zero on error.
+ */
+int Entry2::fill_in_widgets_info (const char *fmt, va_list args)
+{
+  size_t f = 0;
+  const char *last_literal = 0;
+  const int F_PLUS     = 1;
+  const int F_MINUS    = 2;
+  const int F_ZERO     = 4;
+  const int L_OMITTED  = 65535;
+  const int L_ASTERISK = 65534;
+  
+  /* First step: parse <fmt> and fill in
+     <box_len>, <buf_max_len>, <box_len>,
+     <caption> <entry_flags>. */
+
+  for (const char *p = fmt;;)
+  {
+    if (*p == '%')
+    {
+      p++;
+      // Got %%
+      if (*p == '%')
+      {
+	if (! last_literal)
+	  last_literal = p - 1;
+	p++;
+	continue;
+      }
+      // Got a real %-field
+      if (f >= nfields)
+      {
+	printf ("Internal error: at offset %d in widget fmt \"%s\": more than"
+	    " %d fields.\nIgnoring excess field(s)\n",
+	    (int) (p - fmt), fmt, (int) f);
+	break;
+      }
+      int flags     = 0;
+      int length    = L_OMITTED;
+      int precision = L_OMITTED;
+      char type      = 0;
+      // Get the flag
+      for (;;)
+      {
+	if (*p == '+')
+	{
+	  flags |= F_PLUS;
+	  p++;
+	}
+	else if (*p == '-')
+	{
+	  flags |= F_MINUS;
+	  p++;
+	}
+	else if (*p == '0')
+	{
+	  flags |= F_ZERO;
+	  p++;
+	}
+	else
+	  break;
+      }
+      // Get the optional length
+      if (*p == '*')
+      {
+	length = L_ASTERISK;
+	p++;
+      }
+      else if (isdigit ((unsigned char) *p))
+      {
+	length = 0;
+	while (isdigit ((unsigned char) *p))
+	  length = 10 * length + dectoi (*p++);
+      }
+      // Get the optional precision
+      if (*p == '.')
+      {
+	p++;
+	if (*p == '*')
+	{
+	  precision = L_ASTERISK;
+	  p++;
+	}
+	else if (! isdigit ((unsigned char) *p))
+	{
+	  printf ("Internal error: at offset %d in widget fmt \"%s\": bad"
+	      " precision spec \"%c\"\n", (int) (p - fmt), fmt, *p);
+	  break;
+	}
+	else
+	{
+	  precision = 0;
+	  while (isdigit ((unsigned char) *p))
+	    precision = 10 * precision + dectoi (*p++);
+	}
+      }
+      // Get the optional modifier (hh, h, l or Z)
+      _field_flags_t size = FF_INT;
+      if (*p == 'h')
+      {
+	if (p[1] == 'h')
+	{
+	  size = FF_CHAR;
+	  p += 2;
+	}
+	else
+	{
+	  size = FF_SHORT;
+	  p++;
+	}
+      }
+      else if (*p == 'Z')
+      {
+	size = FF_SIZE_T;
+	p++;
+      }
+      else if (*p == 'l')
+      {
+	size = FF_LONG;
+	p++;
+      }
+      // Get the type (diousSxX)
+      if (*p == 'd' || *p == 'i' || *p == 'o' || *p == 'x' || *p == 'X')
+	type = 'd';
+      else if (*p == 'u')
+	type = 'u';
+      else if (*p == 's')
+	type = 's';
+      else if (*p == 'S')
+	type = 'S';
+      else
+      {
+	printf ("Internal error: at offset %d in widget fmt \"%s\": bad"
+	    " format \"%c\"\n", (int) (p - fmt), fmt, *p);
+	continue;
+      }
+      p++;
+
+      /* Fill in <entry_flags> and <caption> and
+	 also <box_len> and <buf_max_len> if
+	 they're explicit. */
+      box_len[f] = precision;
+      buf[f] = 0;
+      buf_max_len[f] = length;
+      if (type == 'd')
+	entry_flags[f] = (_field_flags_t) (FF_ENTRY | FF_INTEGER | FF_SIGNED);
+      else if (type == 'u')
+	entry_flags[f] = (_field_flags_t) (FF_ENTRY | FF_INTEGER);
+      else if (type == 's' || type == 'S')
+      {
+	entry_flags[f] = (_field_flags_t) (FF_ENTRY | FF_STRING);
+	if (type == 'S')
+	  entry_flags[f] = (_field_flags_t) (entry_flags[f] | FF_UPPERCASE);
+	if (flags & F_PLUS)
+	  entry_flags[f] = (_field_flags_t) (entry_flags[f] | FF_NONEMPTY);
+      }
+      else
+	entry_flags[f] = (_field_flags_t) 0;  // Ouch !
+      caption[f]     = last_literal;
+
+      // On to the next field
+      f++;
+      last_literal = 0;
+    }
+    else
+    {
+      if (*p == '\0')
+	break;
+      if (! last_literal)
+	last_literal = p;
+      p++;
+    }
+  }
+
+  /* Second phase: retrieve the arguments from
+     the list and fill in <buf> and perhaps also
+     <box_len> and <buf_max_len> if needed. */
+  for (size_t f = 0; f < nfields; f++)
+  {
+    // "%*": retrieve the length
+    if (buf_max_len[f] == L_ASTERISK)
+      buf_max_len[f] = va_arg (args, size_t);
+
+    // "%.*": retrieve the precision
+    if (box_len[f] == L_ASTERISK)
+      box_len[f] = va_arg (args, size_t);
+
+    // Retrieve the pointer on the buffer
+    if ((entry_flags[f] & FF_TYPE) == FF_ENTRY)
+    {
+      if ((entry_flags[f] & FF_SUBTYPE) == FF_STRING)
+      {
+        buf[f] = va_arg (args, char *);
+        if (buf_max_len[f] == L_OMITTED)
+	  buf_max_len[f] = strlen (buf[f]);  // Bletch !
+	if (box_len[f] == L_OMITTED)
+	  box_len[f] = y_min (buf_max_len[f], 30);
+      }
+      else if ((entry_flags[f] & FF_SUBTYPE) == FF_INTEGER)
+      {
+	switch (entry_flags[f] & FF_INTSIZE)
+	{
+	  case FF_CHAR :
+	    buf[f] = (char *) va_arg (args, char *);
+	    break;
+	  case FF_SHORT :
+	    buf[f] = (char *) va_arg (args, short *);
+	    break;
+	  case FF_INT :
+	    buf[f] = (char *) va_arg (args, int *);
+	    break;
+	  case FF_SIZE_T :
+	    buf[f] = (char *) va_arg (args, size_t *);
+	    break;
+	  case FF_LONG :
+	    buf[f] = (char *) va_arg (args, long *);
+	    break;
+	  default :
+	    ;  // FIXME
+	}
+      }
+      else 
+	;  // FIXME
+    }
+    else
+      ;  // To be implemented later
+  }
+  return 0;
+}
+
+ 
+/*
+ *	do_geom
+ *	Do geometry computations
+ */
+void Entry2::do_geom ()
+{
+  // Compute the widths
+  size_t title_len = strlen (title);	// Length of title
+  size_t entry_len = 0;			// Length or longest entry
+  for (size_t f = 0; f < nfields; f++)
+  {
+    size_t l = box_len[f];
+    if (l > entry_len)
+      entry_len = l;
+  }
+  size_t caption_len = 0;		// Length of longest caption
+  for (size_t f = 0; f < nfields; f++)
+  {
+    size_t l = strlen (caption[f]);
+    if (l > caption_len)
+      caption_len = l;
+  }
+  size_t entry_width  = FONTW * entry_len + 2 * entry_hofs;
+  size_t caption_width= FONTW * caption_len + WIDE_HSPACING;
+  size_t inner_width  = y_max (entry_width + caption_width, FONTW * title_len);
+  size_t outer_width  = inner_width  + 2 * win_hofs;
+
+  // Compute the heights
+  vstep = FONTH + 2 * entry_vofs + BOX_VSPACING;
+  size_t inner_height = nfields * vstep - BOX_VSPACING + title_vspacing + FONTH;
+  size_t outer_height = inner_height + 2 * win_vofs;
+
+  // Compute the absolute coordinates
+  if (win_x0 < 0)
+     win_x0 = (ScrMaxX - outer_width) / 2;
+  if (win_y0 < 0)
+     win_y0 = (ScrMaxY - outer_height) / 2;
+  win_x1        = win_x0 + outer_width - 1;
+  win_y1        = win_y0 + outer_height - 1;
+  title_x0      = win_x0 + win_hofs;
+  title_y0      = win_y0 + win_vofs;
+  entry_box_y0  = title_y0 + FONTH + title_vspacing;
+  entry_text_y0 = entry_box_y0 + entry_vofs;
+  entry_text_y1 = entry_text_y0 + FONTH - 1;
+  entry_box_y1  = entry_text_y1 + entry_vofs;
+  caption_y0    = entry_text_y0;
+  caption_x0    = title_x0;
+  entry_box_x0  = caption_x0 + caption_width;
+  entry_text_x0 = entry_box_x0 + entry_hofs;
+  entry_text_x1 = entry_text_x0 + entry_len * FONTW - 1;  // Unused
+  entry_box_x1  = entry_text_x1 + entry_hofs;             // Unused
+
+  geom_up_to_date = true;
+}
+
+
+/*
+ *	jump_to_field
+ *	Jump to a particular field
+ */
+void Entry2::jump_to_field (size_t field_no)
+{
+  if (field_no >= nfields)
+  {
+    printf ("Internal error: Entry2::jump_to_field %d (nf=%d)",
+	(int) field_no, (int) nfields);
+    return;
+  }
+  entry_drawn[this->field_no] = false;
+  entry_drawn[field_no] = false;
+  this->field_no = field_no;
+  first_key = 1;
+}
+
+
+/*
+ *	prev_field
+ */
+void Entry2::prev_field ()
+{
+  if (nfields < 1)
+    return;
+  size_t f = field_no;
+  if (f < 1)
+    f = nfields - 1;
+  else
+    f--;
+  jump_to_field (f);
+}
+
+
+/*
+ *	next_field
+ */
+void Entry2::next_field ()
+{
+  if (nfields < 1)
+    return;
+  size_t f = field_no + 1;
+  if (f >= nfields)
+    f = 0;
+  jump_to_field (f);
+}
+
+
+/* TEST STUFF FOLLOWS */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/entry2.h	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,122 @@
+/*
+ *	entry2.h
+ *	A string entry box class
+ *	AYM 1999-04-12
+ */
+
+
+#ifndef YH_ENTRY2  /* To prevent multiple inclusion */
+#define YH_ENTRY2  /* To prevent multiple inclusion */
+
+
+typedef enum
+{
+  ACT_NONE,
+  ACT_VALID,
+  ACT_CANCEL
+} Entry2_action_t;
+
+
+class Entry2
+{
+  typedef enum  // Strictly private to the class
+  {
+    FF_TYPE      = 0xf000,  // Type mask
+      FF_ENTRY   = 0x0000,  //   Entry
+      FF_CHECK   = 0x1000,  //   Check button (unimplemented)
+      FF_RADIO   = 0x2000,  //   Radio button (unimplemented)
+      FF_BUTTON  = 0x3000,  //   Button (unimplemented)
+    FF_SUBTYPE   = 0x0f00,  // Subtype mask
+      FF_STRING  = 0x0000,  //   Entry: String entry
+      FF_INTEGER = 0x0100,  //   Entry: Integer entry
+    FF_UPPERCASE = 0x0001,  // String entry: upper-case everything
+    FF_NONEMPTY  = 0x0002,  // String entry: can't be empty
+    FF_SIGNED    = 0x0001,  // Integer entry: it can be signed (unimplemented)
+    FF_INTSIZE   = 0x000e,  // Integer entry: size mask
+      FF_CHAR    = 0x0000,  //   char (signed or unsigned)
+      FF_SHORT   = 0x0002,  //   short (signed or unsigned)
+      FF_INT     = 0x0004,  //   int  (signed or unsigned)
+      FF_SIZE_T  = 0x0006,  //   size_t
+      FF_LONG    = 0x0008,  //   long (signed or unsigned)
+    FF__
+  } _field_flags_t;
+
+  public :
+
+    Entry2 (const char *title, const char *fmt, ...);
+    ~Entry2 ();
+    int loop ();
+    Entry2_action_t process_event (const input_status_t &is);
+    void refresh ();
+
+  private :
+
+    int count_widgets (const char *fmt);
+    int fill_in_widgets_info (const char *fmt, va_list args);
+    void do_geom ();
+    void jump_to_field (size_t field_no);
+    void prev_field ();
+    void next_field ();
+
+    // Per-field data
+    unsigned short  *box_len;
+    char           **buf;
+    unsigned short  *buf_max_len;
+    const char     **caption;
+    bool            *entry_drawn;
+    _field_flags_t *entry_flags;
+
+    // Input
+    bool first_key;
+    size_t field_no;
+    size_t nfields;
+
+    // General display stuff
+    const char *title;
+    bool background_drawn;
+
+    // Geometry constants
+    int entry_hofs;
+    int entry_vofs;
+    int win_hofs;
+    int win_vofs;
+    int title_vspacing;
+
+    // Geometry stuff
+    bool geom_up_to_date;
+    int outer_width;
+    int outer_height;
+    int vstep;
+    int win_x0;
+    int win_y0;
+    int win_x1;
+    int win_y1;
+    int title_x0;
+    int title_y0;
+    int caption_x0;
+    int caption_y0;
+    int entry_box_x0;
+    int entry_box_y0;
+    int entry_box_x1;
+    int entry_box_y1;
+    int entry_text_x0;
+    int entry_text_y0;
+    int entry_text_x1;
+    int entry_text_y1;
+
+    // Convenience functions.
+    bool is_integer_entry (_field_flags_t flags)
+    {
+      return (flags & FF_TYPE) == FF_ENTRY
+	&& (flags & FF_SUBTYPE) == FF_INTEGER;
+    }
+
+    bool is_string_entry (_field_flags_t flags)
+    {
+      return (flags & FF_TYPE) == FF_ENTRY
+	&& (flags & FF_SUBTYPE) == FF_STRING;
+    }
+};
+
+
+#endif  /* DO NOT ADD ANYTHING AFTER THIS LINE */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/events.cc	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,136 @@
+/*
+ *	events.c
+ *	Half baked internal event handling.
+ *	AYM 1998-11-09
+ */
+
+
+/*
+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.
+*/
+
+
+/*
+This module sucks TOTALLY !
+Issues :
+- should functions that take an event type as a criterion
+  limit themselves to the last event or look the entire
+  queue ?
+- should probably group all YK_* events under the type
+  YE_KEYPRESS and put the exact key number in a struct
+  field,
+- and more...
+*/
+
+
+#include "yadex.h"
+#include "events.h"
+
+
+// Number of cells in the event queue (actually a circular
+// buffer). The queue can actually hold only that number
+// minus one events.
+#define Y_EVENT_QUEUE 100
+static int event_queue[Y_EVENT_QUEUE];
+// Index of the head and tail of the circular buffer.
+// At any moment, the next event to get is in event_queue[head]
+// and the next put will be put in event_queue[tail]
+static int head = 0;
+static int events_in_queue = 0;
+
+
+
+/*
+ *
+ */
+void init_event ()
+{
+  head = 0;
+  events_in_queue = 0;
+}
+
+
+/*
+ *
+ */
+void send_event (int event)
+{
+  if (events_in_queue == Y_EVENT_QUEUE)
+    fatal_error ("Event buffer full");
+  event_queue[(head + events_in_queue) % Y_EVENT_QUEUE] = event;
+  events_in_queue++;
+}
+
+
+/*
+ *	has_event
+ *	Is there any event at all ?
+ */
+int has_event ()
+{
+  return events_in_queue != 0;
+}
+
+
+/*
+ *	has_event
+ *	Is there an event of that type ?
+ */
+int has_event (int event)
+{
+  return events_in_queue != 0
+    && event_queue[head] == event;
+}
+
+
+/*
+ *	has_key_press_event
+ *	Is there an YK_* event ?
+ *	FIXME should create YE_KEY_PRESS and delete this function.
+ */
+int has_key_press_event ()
+{
+  return events_in_queue != 0
+    && event_queue[head]
+    && (event_queue[head] & ~ (YK_ALT | YK_CTRL | YK_SHIFT)) < YK__LAST;
+}
+
+
+/*
+ *	get_event
+ *	Get the next event
+ */
+int get_event ()
+{
+  if (events_in_queue == 0)  // The buffer is empty
+    return 0;
+
+  int e = event_queue[head];
+  events_in_queue--;
+  head++;
+  if (head == Y_EVENT_QUEUE)
+    head = 0;
+  return e;
+}
+
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/events.h	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,21 @@
+/*
+ *	events.h
+ *	AYM 1998-11-09
+ */
+
+
+/*
+The idea here is to have the application generate
+events internally (as opposed to X event passed
+by get_input_status()).
+It's still _only_ an idea ; this API is bogus.
+*/
+
+void init_event ();
+void send_event (int);
+int has_event ();
+int has_event (int);
+int has_key_press_event ();
+int get_event ();
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/flats.cc	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,169 @@
+/*
+ *	flats.cc
+ *	AYM 1998-??-??
+ */
+
+
+/*
+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"
+#ifdef Y_X11
+#include <X11/Xlib.h>
+#endif
+#include "flats.h"
+#include "gfx.h"
+#include "img.h"
+#include "levels.h"
+#include "lists.h"
+#include "sticker.h"
+#include "wadfile.h"
+#include "wads.h"
+
+
+/*
+   choose a floor or ceiling texture
+   FIXME the <list> and <listsize> parameters are ignored since 1999-07-10.
+*/
+
+void ChooseFloorTexture (int x0, int y0, const char *prompt, int listsize, char **list, char *name)
+{
+  (void) list;
+  (void) listsize;
+  // Build a list of char *, for InputNameFromListWithFunc()'s sake
+  char **flat_names = (char **) GetMemory (NumFTexture * sizeof *flat_names);
+  for (size_t n = 0; n < NumFTexture; n++)
+    flat_names[n] = flat_list[n].name;
+
+  HideMousePointer ();
+
+  SwitchToVGA256 ();
+  /* If we only have a 320x200x256 VGA driver, we must change x0 and y0.
+     Yuck! */
+  if (GfxMode > -2)
+  {
+    x0 = -1;
+    y0 = -1;
+  }
+  InputNameFromListWithFunc (x0, y0, prompt, (size_t) NumFTexture, flat_names,
+    5, name, 64, 64, DisplayFloorTexture);
+
+  SwitchToVGA16 ();
+
+  ShowMousePointer ();
+  FreeMemory (flat_names);
+}
+
+
+/*
+ *	flat_list_entry_match
+ *	Function used by bsearch() to locate a particular 
+ *	flat in the FTexture.
+ */
+static int flat_list_entry_match (const void *key, const void *flat_list_entry)
+{
+  return y_strnicmp ((const char *) key,
+    ((const flat_list_entry_t *) flat_list_entry)->name,
+    WAD_FLAT_NAME);
+}
+
+
+/*
+   display a floor or ceiling texture at coords c->x0, c->y0
+   and not beyond c->x1, c->y1
+*/
+
+void DisplayFloorTexture (hookfunc_comm_t *c)
+{
+  c->width  = DOOM_FLAT_WIDTH;  // Big deal !
+  c->height = DOOM_FLAT_HEIGHT;
+  c->flags  = HOOK_SIZE_VALID;
+
+  flat_list_entry_t *flat = (flat_list_entry_t *)
+    bsearch (c->name, flat_list, NumFTexture, sizeof *flat_list,
+	flat_list_entry_match);
+  if (flat == 0)  // Not found in list
+  {
+    push_colour (WINBG);
+    DrawScreenBox (c->x0, c->y0, c->x1, c->y1);
+    set_colour (WINFG_DIM);
+    DrawScreenLine (c->x0, c->y0, c->x1, c->y1);
+    DrawScreenLine (c->x0, c->y1, c->x1, c->y0);
+    pop_colour ();
+    return;
+  }
+  c->lump_loc.wad = flat->wadfile;
+  c->lump_loc.ofs = flat->offset;
+  c->lump_loc.len = DOOM_FLAT_WIDTH * DOOM_FLAT_HEIGHT;  // Sorry.
+  c->flags |= HOOK_LOC_VALID;
+  const Wad_file *wadfile = flat->wadfile;
+  wadfile->seek (flat->offset);
+  if (wadfile->error ())
+  {
+    warn ("%s: can't seek to %lXh\n",
+	wadfile->pathname (), (unsigned long) flat->offset);
+    warn ("%.8s: seek error\n", c->name);
+  }
+
+  c->img.resize (c->width, c->height);
+  c->img.set_opaque (true);
+  long nbytes = (long) c->width * c->height;
+  wadfile->read_bytes (c->img.wbuf (), nbytes);
+  if (wadfile->error ())
+  {
+    warn ("%s: read error\n", wadfile->where ());
+    warn ("%.8s: short read\n", c->name);
+  }
+  Sticker sticker (c->img, true);  // Use opaque because it's faster
+  sticker.draw (drw, 't', c->x0, c->y0);
+
+  c->disp_x0 = c->x0;
+  c->disp_y0 = c->y0;
+  c->disp_x1 = c->x1;
+  c->disp_y1 = c->y1;
+
+  c->flags |= HOOK_DRAWN;
+}
+
+
+/*
+ *	display_flat_depressed
+ *	Display a flat inside a hollow box
+ */
+void display_flat_depressed (hookfunc_comm_t *c)
+{
+  draw_box_border (c->x0, c->y0, c->x1 - c->x0 + 1, c->y1 - c->y0 + 1,
+    HOLLOW_BORDER, 0);
+  c->x0 += HOLLOW_BORDER;
+  c->y0 += HOLLOW_BORDER;
+  c->x1 -= HOLLOW_BORDER;
+  c->y1 -= HOLLOW_BORDER;
+  DisplayFloorTexture (c);
+  c->x0 -= HOLLOW_BORDER;
+  c->y0 -= HOLLOW_BORDER;
+  c->x1 += HOLLOW_BORDER;
+  c->y1 += HOLLOW_BORDER;
+}
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/flats.h	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,19 @@
+/*
+ *	flats.h
+ *	AYM 1998-nn-nn
+ */
+
+
+#ifndef YH_FLATS  /* DO NOT INSERT ANYTHING BEFORE THIS LINE */
+#define YH_FLATS
+
+
+#include "lists.h"
+
+
+void ChooseFloorTexture (int, int, const char *, int, char **, char *);
+void DisplayFloorTexture (hookfunc_comm_t *c);
+void display_flat_depressed (hookfunc_comm_t *c);
+
+
+#endif  /* DO NOT ADD ANYTHING AFTER THIS LINE */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/game.cc	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,420 @@
+/*
+ *	game.cc
+ *	Load .ygd file (Yadex Game Definitions)
+ *	AYM 1998-01-04
+ */
+
+
+/*
+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 "acolours.h"
+#include "game.h"
+#include "gamesky.h"
+#include "locate.h"
+#include "things.h"
+#include "trace.h"
+
+
+const char ygd_file_magic[] = "# Yadex game definition file version 4";
+
+
+/*
+ *	InitGameDefs
+ *	Create empty lists for game definitions
+ */
+void InitGameDefs (void)
+{
+ldtdef      = al_lcreate (sizeof (ldtdef_t    ));
+ldtgroup    = al_lcreate (sizeof (ldtgroup_t  ));
+stdef       = al_lcreate (sizeof (stdef_t     ));
+thingdef    = al_lcreate (sizeof (thingdef_t  ));
+thinggroup  = al_lcreate (sizeof (thinggroup_t));
+}
+
+
+/*
+ *	LoadGameDefs
+ *	Looks for file <game>.ygd in various directories and reads it.
+ *	Builds list ThingsDefs.
+ *	A totally boring piece of code.
+ */
+void LoadGameDefs (const char *game)
+{
+FILE *ygdfile = 0;		/* YGD file descriptor */
+#define YGD_BUF 200		/* max. line length + 2 */
+char readbuf[YGD_BUF];		/* buffer the line is read into */
+#define MAX_TOKENS 10		/* tokens per line */
+int lineno;			/* current line of file */
+char filename[1025];
+char basename[256];
+
+al_scps (basename, game,   sizeof basename - 1);
+al_saps (basename, ".ygd", sizeof basename - 1);
+
+/* Locate the game definition file. */
+{
+   Locate locate (yadex_share_path, basename, false);
+   const char *pathname = locate.get_next ();
+   if (pathname == NULL)
+      fatal_error ("Game definition file \"%s\" not found", basename);
+   if (strlen (pathname) > sizeof filename - 1)
+      fatal_error ("%s: file name too long");
+   strcpy (filename, pathname);
+   printf ("Reading game definition file \"%s\".\n", filename);
+}
+
+ygdfile = fopen (filename, "r");
+if (ygdfile == NULL)
+   fatal_error ("%s: %s", filename, strerror (errno));
+
+/* The first line of the ygd file must
+   contain exactly ygd_file_magic. */
+if (fgets (readbuf, sizeof readbuf, ygdfile) == NULL
+   || memcmp (readbuf, ygd_file_magic, sizeof ygd_file_magic - 1)
+   || readbuf[sizeof ygd_file_magic - 1] != '\n'
+   || readbuf[sizeof ygd_file_magic] != '\0')
+   {
+   err ("%s is not a valid Yadex game definition file", filename);
+   fatal_error ("Perhaps a leftover from a previous version of Yadex ?");
+   }
+
+/* Read the game definition
+   file, line by line. */
+for (lineno = 2; fgets (readbuf, sizeof readbuf, ygdfile); lineno++)
+   {
+   int         ntoks;
+   char       *token[MAX_TOKENS];
+   int         quoted;
+   int         in_token;
+   const char *iptr;
+   char       *optr;
+   char       *buf;
+   const char *const bad_arg_count =
+                                "%s(%d): directive \"%s\" takes %d parameters";
+
+   /* duplicate the buffer */
+   buf = (char *) malloc (strlen (readbuf) + 1);
+   if (! buf)
+      fatal_error ("not enough memory");
+   
+   /* break the line into whitespace-separated tokens.
+      whitespace can be enclosed in double quotes. */
+   for (in_token = 0, quoted = 0, iptr = readbuf, optr = buf, ntoks = 0;
+    ; iptr++)
+      {
+      if (*iptr == '\n' || *iptr == '\0')
+	 {
+	 if (in_token)
+	   *optr = '\0';
+	 break;
+	 }
+
+      else if (*iptr == '"')
+	 quoted ^= 1;
+
+      // "#" at the beginning of a token
+      else if (! in_token && ! quoted && *iptr == '#')
+         break;
+
+      // First character of token
+      else if (! in_token && (quoted || ! isspace (*iptr)))
+	 {
+         if (ntoks >= (int) (sizeof token / sizeof *token))
+            fatal_error ("%s(%d): more than %d tokens",
+               filename, lineno, sizeof token / sizeof *token);
+	 token[ntoks] = optr;
+	 ntoks++;
+	 in_token = 1;
+	 *optr++ = *iptr;
+	 }
+
+      // First space between two tokens
+      else if (in_token && ! quoted && isspace (*iptr))
+	 {
+	 *optr++ = '\0';
+	 in_token = 0;
+	 }
+
+      // Character in the middle of a token
+      else if (in_token)
+	 *optr++ = *iptr;
+      }
+   if (quoted)
+      fatal_error ("%s(%d): unmatched double quote", filename, lineno);
+
+   /* process line */
+   if (ntoks == 0)
+      {
+      free (buf);
+      continue;
+      }
+   if (! strcmp (token[0], "ldt"))
+      {
+      ldtdef_t buf;
+
+      if (ntoks != 5)
+	 fatal_error (bad_arg_count, filename, lineno, token[0], 4);
+      buf.number    = atoi (token[1]);
+      buf.ldtgroup  = *token[2];
+      buf.shortdesc = token[3];  /* FIXME: trunc to 16 char. */
+      buf.longdesc  = token[4];  /* FIXME: trunc reasonably */
+      if (al_lwrite (ldtdef, &buf))
+	 fatal_error ("LGD1 (%s)", al_astrerror (al_aerrno));
+      }
+   else if (! strcmp (token[0], "ldtgroup"))
+      {
+      ldtgroup_t buf;
+
+      if (ntoks != 3)
+	 fatal_error (bad_arg_count, filename, lineno, token[0], 2);
+      buf.ldtgroup = *token[1];
+      buf.desc     = token[2];
+      if (al_lwrite (ldtgroup, &buf))
+	 fatal_error ("LGD2 (%s)", al_astrerror (al_aerrno));
+      }
+   else if (! strcmp (token[0], "level_format"))
+      {
+      if (ntoks != 2)
+	 fatal_error (bad_arg_count, filename, lineno, token[0], 1);
+      if (! strcmp (token[1], "alpha"))
+	 yg_level_format = YGLF_ALPHA;
+      else if (! strcmp (token[1], "doom"))
+         yg_level_format = YGLF_DOOM;
+      else if (! strcmp (token[1], "hexen"))
+         yg_level_format = YGLF_HEXEN;
+      else
+	 fatal_error ("%s(%d): invalid argument \"%.32s\" (alpha|doom|hexen)",
+            filename, lineno, token[1]);
+      free (buf);
+      }
+   else if (! strcmp (token[0], "level_name"))
+      {
+      if (ntoks != 2)
+	 fatal_error (bad_arg_count, filename, lineno, token[0], 1);
+      if (! strcmp (token[1], "e1m1"))
+         yg_level_name = YGLN_E1M1;
+      else if (! strcmp (token[1], "e1m10"))
+         yg_level_name = YGLN_E1M10;
+      else if (! strcmp (token[1], "map01"))
+         yg_level_name = YGLN_MAP01;
+      else
+	 fatal_error ("%s(%d): invalid argument \"%.32s\" (e1m1|e1m10|map01)",
+            filename, lineno, token[1]);
+      free (buf);
+      }
+   else if (! strcmp (token[0], "picture_format"))
+      {
+      if (ntoks != 2)
+         fatal_error (bad_arg_count, filename, lineno, token[0], 1);
+      if (! strcmp (token[1], "alpha"))
+	 yg_picture_format = YGPF_ALPHA;
+      else if (! strcmp (token[1], "pr"))
+	 yg_picture_format = YGPF_PR;
+      else if (! strcmp (token[1], "normal"))
+	 yg_picture_format = YGPF_NORMAL;
+      else
+	 fatal_error ("%s(%d): invalid argument \"%.32s\" (alpha|pr|normal)",
+	    filename, lineno, token[1]);
+      free (buf);
+      }
+   else if (! strcmp (token[0], "sky_flat"))
+      {
+      if (ntoks != 2)
+	 fatal_error (bad_arg_count, filename, lineno, token[0], 1);
+      sky_flat = token[1];
+      }
+   else if (! strcmp (token[0], "st"))
+      {
+      stdef_t buf;
+
+      if (ntoks != 4)
+	 fatal_error (bad_arg_count, filename, lineno, token[0], 3);
+      buf.number    = atoi (token[1]);
+      buf.shortdesc = token[2];  /* FIXME: trunc to 14 char. */
+      buf.longdesc  = token[3];  /* FIXME: trunc reasonably */
+      if (al_lwrite (stdef, &buf))
+	 fatal_error ("LGD3 (%s)", al_astrerror (al_aerrno));
+      }
+   else if (! strcmp (token[0], "texture_format"))
+      {
+      if (ntoks != 2)
+         fatal_error (bad_arg_count, filename, lineno, token[0], 1);
+      if (! strcmp (token[1], "nameless"))
+	 yg_texture_format = YGTF_NAMELESS;
+      else if (! strcmp (token[1], "normal"))
+	 yg_texture_format = YGTF_NORMAL;
+      else if (! strcmp (token[1], "strife11"))
+	 yg_texture_format = YGTF_STRIFE11;
+      else
+	 fatal_error (
+	    "%s(%d): invalid argument \"%.32s\" (normal|nameless|strife11)",
+	    filename, lineno, token[1]);
+      free (buf);
+      }
+   else if (! strcmp (token[0], "texture_lumps"))
+      {
+      if (ntoks != 2)
+         fatal_error (bad_arg_count, filename, lineno, token[0], 1);
+      if (! strcmp (token[1], "textures"))
+	 yg_texture_lumps = YGTL_TEXTURES;
+      else if (! strcmp (token[1], "normal"))
+	 yg_texture_lumps = YGTL_NORMAL;
+      else if (! strcmp (token[1], "none"))
+	 yg_texture_lumps = YGTL_NONE;
+      else
+	 fatal_error (
+	    "%s(%d): invalid argument \"%.32s\" (normal|textures|none)",
+	    filename, lineno, token[1]);
+      free (buf);
+      }
+   else if (! strcmp (token[0], "thing"))
+      {
+      thingdef_t buf;
+
+      if (ntoks < 6 || ntoks > 7)
+	 fatal_error (
+            "%s(d%): directive \"%s\" takes between 5 and 6 parameters",
+            filename, lineno, token[0]);
+      buf.number     = atoi (token[1]);
+      buf.thinggroup = *token[2];
+      buf.flags      = *token[3] == 's' ? THINGDEF_SPECTRAL : 0;  // FIXME!
+      buf.radius     = atoi (token[4]);
+      buf.desc       = token[5];
+      buf.sprite     = ntoks >= 7 ? token[6] : 0;
+      if (al_lwrite (thingdef, &buf))
+	 fatal_error ("LGD4 (%s)", al_astrerror (al_aerrno));
+      }
+   else if (! strcmp (token[0], "thinggroup"))
+      {
+      thinggroup_t buf;
+
+      if (ntoks != 4)
+	 fatal_error (bad_arg_count, filename, lineno, token[0], 3);
+      buf.thinggroup = *token[1];
+      if (getcolour (token[2], &buf.rgb))
+	 fatal_error ("%s(%d): bad colour spec \"%.32s\"",
+            filename, lineno, token[2]);
+      buf.acn = add_app_colour (buf.rgb);
+      buf.desc = token[3];
+      if (al_lwrite (thinggroup, &buf))
+	 fatal_error ("LGD5 (%s)", al_astrerror (al_aerrno));
+      }
+   else
+      {
+      free (buf);
+      fatal_error ("%s(%d): unknown directive \"%.32s\"",
+	 filename, lineno, token[0]);
+      }
+   }
+
+fclose (ygdfile);
+
+/* Verify that all the mandatory directives are present. */
+{
+bool abort = false;
+if (yg_level_format == YGLF__)
+   {
+   err ("%s: Missing \"level_format\" directive.", filename);
+   abort = true;
+   }
+if (yg_level_name == YGLN__)
+   {
+   err ("%s: Missing \"level_name\" directive.", filename);
+   abort = true;
+   }
+// FIXME perhaps print a warning message if picture_format
+// is missing ("assuming picture_format=normal").
+// FIXME and same thing for texture_format and texture_lumps ?
+if (abort)
+   exit (2);
+}
+
+#if 0
+
+#endif
+
+/*
+ *	Second pass
+ */
+
+/* Speed optimization : build the table of things attributes
+   that get_thing_*() use. */
+create_things_table ();
+
+/* KLUDGE: Add bogus ldtgroup LDT_FREE. InputLinedefType()
+   knows that it means "let the user enter a number". */
+{
+ldtgroup_t buf;
+
+buf.ldtgroup = LDT_FREE;  /* that is '\0' */
+buf.desc     = "Other (enter number)";
+al_lseek (ldtgroup, 0, SEEK_END);
+if (al_lwrite (ldtgroup, &buf))
+  fatal_error ("LGD90 (%s)", al_astrerror (al_aerrno));
+}
+
+/* KLUDGE: Add bogus thinggroup THING_FREE.
+   InputThingType() knows that it means "let the user enter a number". */
+{
+thinggroup_t buf;
+
+buf.thinggroup = THING_FREE;  /* that is '\0' */
+buf.desc       = "Other (enter number)";
+al_lseek (thinggroup, 0, SEEK_END);
+if (al_lwrite (thinggroup, &buf))
+  fatal_error ("LGD91 (%s)", al_astrerror (al_aerrno));
+}
+
+/* KLUDGE: Add bogus sector type at the end of stdef.
+   SectorProperties() knows that it means "let the user enter a number". */
+{
+stdef_t buf;
+
+buf.number    = 0;     /* not significant */
+buf.shortdesc = 0;     /* not significant */
+buf.longdesc  = "Other (enter number)";
+al_lseek (stdef, 0, SEEK_END);
+if (al_lwrite (stdef, &buf))
+  fatal_error ("LGD92 (%s)", al_astrerror (al_aerrno));
+}
+
+}
+
+
+/*
+ *	FreeGameDefs
+ *	Free all memory allocated to game definitions
+ */
+void FreeGameDefs (void)
+{
+delete_things_table ();
+al_ldiscard (ldtdef    );
+al_ldiscard (ldtgroup  );
+al_ldiscard (stdef     );
+al_ldiscard (thingdef  );
+al_ldiscard (thinggroup);
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/game.h	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,97 @@
+/*
+ *	game.h
+ *	Header for game.cc
+ *	AYM 19980129
+ */
+
+
+#include "rgb.h"
+
+
+extern const char ygd_file_magic[];
+
+
+/*
+ *	Data structures for game definition data
+ */
+
+// ldt <number> <ldtgroup> <shortdesc> <longdesc>
+typedef struct
+   {
+   int number;
+   char ldtgroup;
+   const char *shortdesc;
+   const char *longdesc;
+   } ldtdef_t;
+
+// ldtgroup <ldtgroup> <description>
+typedef struct
+   {
+   char ldtgroup;
+   const char *desc;
+   } ldtgroup_t;
+
+// st <number> <shortdesc> <longdesc>
+typedef struct
+   {
+   int number;
+   const char *shortdesc;
+   const char *longdesc;
+   } stdef_t;
+
+// thing <number> <thinggroup> <flags> <radius> <description> [<sprite>]
+typedef struct
+   {
+   int number;		// Thing number
+   char thinggroup;	// Thing group
+   char flags;		// Flags
+   int radius;		// Radius of thing
+   const char *desc;	// Short description of thing
+   const char *sprite;  // Root of name of sprite for thing
+   } thingdef_t;
+/* (1)  This is only here for speed, to avoid having to lookup
+        thinggroup for each thing when drawing things */
+const char THINGDEF_SPECTRAL = 0x01;
+
+// thinggroup <thinggroup> <colour> <description>
+typedef struct
+   {
+   char thinggroup;	// Thing group
+   rgb_c rgb;		// RGB colour
+   acolour_t acn;	// Application colour#
+   const char *desc;	// Description of thing group
+   } thinggroup_t;
+
+
+/*
+ *	Global variables that contain game definition data
+ *	Those variables are defined in yadex.cc
+ */
+
+typedef enum { YGLF__, YGLF_ALPHA, YGLF_DOOM, YGLF_HEXEN } yglf_t;
+typedef enum { YGLN__, YGLN_E1M10, YGLN_E1M1, YGLN_MAP01 } ygln_t;
+// ygpf_t and ygtf_t are defined in yadex.h
+extern yglf_t yg_level_format;
+extern ygln_t yg_level_name;
+extern ygpf_t yg_picture_format;
+extern ygtf_t yg_texture_format;
+extern ygtl_t yg_texture_lumps;
+extern al_llist_t *ldtdef;
+extern al_llist_t *ldtgroup;
+extern al_llist_t *stdef;
+extern al_llist_t *thingdef;
+extern al_llist_t *thinggroup;
+
+
+// Shorthands to make the code more readable
+#define CUR_LDTDEF     ((ldtdef_t     *)al_lptr (ldtdef    ))
+#define CUR_LDTGROUP   ((ldtgroup_t   *)al_lptr (ldtgroup  ))
+#define CUR_STDEF      ((stdef_t      *)al_lptr (stdef     ))
+#define CUR_THINGDEF   ((thingdef_t   *)al_lptr (thingdef  ))
+#define CUR_THINGGROUP ((thinggroup_t *)al_lptr (thinggroup))
+
+#define LDT_FREE    '\0'  /* KLUDGE: bogus ldt group   (see game.c) */
+#define ST_FREE     '\0'  /* KLUDGE: bogus sector type (see game.c) */
+#define THING_FREE  '\0'  /* KLUDGE: bogus thing group (see game.c) */
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/gamedef.h	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,111 @@
+/*
+ *	gamedef.h - Game_def class
+ *	AYM 2000-08-30
+ */
+
+
+#ifndef YH_GAMEDEF  /* DO NOT INSERT ANYTHING BEFORE THIS LINE */
+#define YH_GAMEDEF
+
+
+class Game_def_priv;
+
+
+typedef struct
+{
+  char ldtgroup;
+  const char *shortdesc;
+  const char *longdesc;
+} linedef_type_t;
+
+
+typedef char linedef_type_group_id_t;
+
+
+typedef struct
+{
+  const char *desc;
+} linedef_type_group_t;
+
+
+typedef struct
+{
+  const char *shortdesc;
+  const char *longdesc;
+} sector_type_t;
+
+
+typedef char thing_type_group_id_t;
+
+
+typedef struct
+{
+  char flags;		// Flags
+  int radius;		// Radius of thing
+  const char *desc;	// Short description of thing
+  const char *sprite;	// Root of name of sprite for thing
+} thing_type_t;
+
+
+const char THINGDEF_SPECTRAL = 0x01;
+
+
+typedef struct
+{
+  char thinggroup;	// Thing group
+  rgb_c rgb;		// RGB colour
+  acolour_t acn;	// Application colour#
+  const char *desc;	// Description of thing group
+} thing_type_group_t;
+
+
+typedef enum { YGLF__, YGLF_ALPHA, YGLF_DOOM, YGLF_HEXEN } yglf_t;
+typedef enum { YGLN__, YGLN_E1M10, YGLN_E1M1, YGLN_MAP01 } ygln_t;
+typedef enum { YGPF_NORMAL, YGPF_ALPHA, YGPF_PR } ygpf_t;
+typedef enum { YGTF_NORMAL, YGTF_NAMELESS, YGTF_STRIFE11 } ygtf_t;
+typedef enum { YGTL_NORMAL, YGTL_TEXTURES, YGTL_NONE } ygtl_t;
+
+
+/* shorthands to make program more readable */
+
+#define LDT_FREE    '\0'  /* KLUDGE: bogus ldt group   (see game.c) */
+#define ST_FREE     '\0'  /* KLUDGE: bogus sector type (see game.c) */
+#define THING_FREE  '\0'  /* KLUDGE: bogus thing group (see game.c) */
+
+
+/*
+ *	Game_def - contain all the definitions relative to a game
+ */
+class Game_def
+{
+  public :
+    Game_def ();
+    ~Game_def ();
+    const linedef_type_t& linedef_type (wad_ldtype_t type) const;
+    const sector_type_t&  sector_type  (wad_stype_t  type) const;
+    const thing_type_t&   thing_type   (wad_ttype_t  type) const;
+    void linedef_type     (wad_ldtype_t type, linedef_type_t& data);
+    void sector_type      (wad_stype_t type,  sector_type_t&  data);
+    void thing_type       (wad_ttype_t type,  thing_type_t&   data);
+    void del_linedef_type (wad_ldtype_t type);
+    void del_sector_type  (wad_stype_t  type);
+    void del_thing_type   (wad_ttype_t  type);
+    int level_format      (yglf_t level_format);
+    int level_name        (yglf_t level_name);
+    int picture_format    (ygpf_t picture_format);
+    int texture_format    (ygtf_t texture_format);
+    int texture_lumps     (ygtl_t texture_lumps);
+    yglf_t level_format   () const;
+    ygln_t level_name     () const;
+    ygpf_t picture_format () const;
+    ygtf_t texture_format () const;
+    ygtl_t texture_lumps  () const;
+
+  private :
+    Game_def            (const Game_def&);	// Too lazy to implement it
+    Game_def& operator= (const Game_def&);	// Too lazy to implement it
+    Game_def_priv *priv;
+};
+
+
+#endif  /* DO NOT ADD ANYTHING AFTER THIS LINE */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/gamesky.h	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,26 @@
+/*
+ *	gamesky.h
+ *	AYM 2000-04-24
+ */
+
+
+#ifndef YH_GAMESKY  /* DO NOT INSERT ANYTHING BEFORE THIS LINE */
+#define YH_GAMESKY
+
+
+#include "wadname.h"
+
+
+extern Wad_name sky_flat;
+
+
+/*
+ *	is_sky - is this flat a sky
+ */
+inline bool is_sky (const char *flat)
+{
+  return sky_flat == flat;
+}
+
+
+#endif  /* DO NOT ADD ANYTHING AFTER THIS LINE */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/gcolour1.cc	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,193 @@
+/*
+ *	gcolour1.cc
+ *	Allocate and free the game colours.
+ *
+ *	By "game colours", I mean the colours used to draw
+ *	the game graphics (flats, textures, sprites), as
+ *	opposed to the "application colours" which don't
+ *	depend on the the game and are used to draw the
+ *	windows, the menus and the map.
+ *
+ *	The application colours are handled in acolours.cc.
+ *
+ *	AYM 1998-11-29
+ */
+
+
+/*
+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 "gcolour1.h"
+#include "gcolour2.h"
+#include "gfx.h"
+#include "img.h"	/* IMG_TRANSP */
+#include "rgb.h"
+#include "wadfile.h"
+#include "wads.h"
+
+
+/*
+ *	alloc_game_colours
+ *	Allocate the DOOM_COLOURS of PLAYPAL no. <playpalnum>.
+ *	Put the DOOM_COLOURS physical colour numbers corresponding
+ *	to the game colours in the <game_colour> array.
+ */
+pcolour_t *alloc_game_colours (int playpalnum)
+{
+MDirPtr dir;
+u8	*dpal;
+pcolour_t *game_colours = 0;
+
+dir = FindMasterDir (MasterDir, "PLAYPAL");
+if (dir == NULL)
+   {
+   warn ("PLAYPAL lump not found.\n");
+   return 0;
+   }
+
+int playpal_count = dir->dir.size / (3 * DOOM_COLOURS);
+if (playpalnum < 0 || playpalnum >= playpal_count)
+   {
+   warn ("playpalnum %d out of range (0-%d). Using #0 instead.\n",
+      playpalnum, playpal_count - 1);
+   playpalnum = 0;
+   }
+
+dpal = (u8 *) GetFarMemory (3 * DOOM_COLOURS);
+dir->wadfile->seek (dir->dir.start);
+if (dir->wadfile->error ())
+   {
+   warn ("%s: can't seek to %lXh\n",
+       dir->wadfile->pathname (), (unsigned long) dir->dir.start);
+   warn ("PLAYPAL: seek error\n");
+   }
+for (int n = 0; n <= playpalnum; n++)
+   {
+   dir->wadfile->read_bytes (dpal, 3 * DOOM_COLOURS);
+   if (dir->wadfile->error ())
+      {
+      warn ("%s: read error\n", dir->wadfile->where ());
+      warn ("PLAYPAL: error reading entry #%d\n", n);
+      }
+   }
+#if defined Y_BGI
+for (int n = 0; n < 3 * DOOM_COLOURS; n++)
+   dpal[n] /= 4;
+_AX = 0x1012;
+_BX = 0;
+_CX = DOOM_COLOURS;
+_ES = FP_SEG (dpal);
+_DX = FP_OFF (dpal);
+__int__ (0x10);
+#elif defined Y_X11
+
+rgb_c rgb_values[DOOM_COLOURS];
+for (size_t n = 0; n < DOOM_COLOURS; n++)
+   {
+   rgb_values[n].r = (u8) dpal[3 * n];
+   rgb_values[n].g = (u8) dpal[3 * n + 1];
+   rgb_values[n].b = (u8) dpal[3 * n + 2];
+   }
+game_colours = alloc_colours (rgb_values, DOOM_COLOURS);
+
+// Find the colour closest to IMG_TRANSP
+{
+  colour0 = IMG_TRANSP;
+  int smallest_delta = INT_MAX;
+
+  for (size_t n = 1; n < DOOM_COLOURS; n++)
+  {
+    int delta = rgb_values[IMG_TRANSP] - rgb_values[n];
+    if (delta < smallest_delta)
+    {
+      colour0 = n;
+      smallest_delta = delta;
+    }
+  }
+  verbmsg ("colours: colour %d remapped to %d (delta %d)\n",
+    IMG_TRANSP, colour0, smallest_delta);
+}
+
+#endif
+FreeFarMemory (dpal);
+return game_colours;
+}
+
+
+/*
+ *	free_game_colours
+ *	Free the game colours allocated by alloc_game_colours()
+ */
+void free_game_colours (pcolour_t *game_colours)
+{
+free_colours (game_colours, DOOM_COLOURS);
+}
+
+
+
+/* This is how I used to calculate
+   the physical colour numbers.
+   Works only on TrueColor/DirectColor visuals. */
+
+#if 0
+/* FIXME this is a gross hack */
+for (n = 0; n < DOOM_COLOURS; n++)
+   {
+   xpv_t r = dpal[3*n];
+   xpv_t g = dpal[3*n+1];
+   xpv_t b = dpal[3*n+2];
+   if (win_vis_class == DirectColor || win_vis_class == TrueColor)
+      {
+      xpv_t r_scaled, g_scaled, b_scaled;
+      if (win_r_ofs + win_r_bits < 8)
+	 r_scaled = r >> (8 - (win_r_ofs + win_r_bits));
+      else
+	 r_scaled = r << (win_r_ofs + win_r_bits - 8) & win_r_mask;
+      if (win_g_ofs + win_g_bits < 8)
+	 g_scaled = g >> (8 - (win_g_ofs + win_g_bits));
+      else
+	 g_scaled = g << (win_g_ofs + win_g_bits - 8) & win_g_mask;
+      if (win_b_ofs + win_b_bits < 8)
+	 b_scaled = b >> (8 - (win_b_ofs + win_b_bits));
+      else
+	 b_scaled = b << (win_b_ofs + win_b_bits - 8) & win_b_mask;
+      game_colour[n] = r_scaled | g_scaled | b_scaled;
+      }
+   else if (win_vis_class== PseudoColor || win_vis_class == StaticColor)
+      game_colour[n] = n;  /* Ugh! */
+   else if (win_vis_class == GrayScale || win_vis_class == StaticGray)
+      {
+      game_colour[n] = (r + g + b) / 3;
+      if (win_depth < 8)
+	 game_colour[n] >>= 8 - win_depth;
+      else
+	 game_colour[n] <<= win_depth - 8;
+      }
+   // printf ("%02X %08lX", n, (unsigned long) game_colour[n]);
+   // if (n % 6 == 5)
+   //    putchar ('\n');
+   // else
+   //    printf ("  ");
+   }
+#endif  /* #if 0 */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/gcolour1.h	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,22 @@
+/*
+ *	gcolour1.h
+ *	Allocate and free the game colours.
+ *
+ *	By "game colours", I mean the colours used to draw
+ *	the game graphics (flats, textures, sprites), as
+ *	opposed to the "application colours" which don't
+ *	depend on the the game and are used to draw the
+ *	windows, the menus and the map.
+ *
+ *	The application colours are handled in acolours.cc.
+ *
+ *	AYM 1998-11-29
+ */
+
+
+#include "colour.h"
+
+
+pcolour_t *alloc_game_colours (int playpalnum);
+void free_game_colours (pcolour_t *game_colours);
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/gcolour2.cc	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,38 @@
+/*
+ *	gcolour2.cc
+ *	The game colour# -> physical colour# conversion table.
+ *	AYM 1998-11-29
+ */
+
+
+/*
+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 "colour.h"
+#include "gcolour2.h"
+
+
+pcolour_t *game_colour = 0;	// Pixel values for the DOOM_COLOURS game clrs.
+int colour0;			// Game colour to which g. colour 0 is remapped
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/gcolour2.h	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,13 @@
+/*
+ *	gcolour2.h
+ *	The game colour# -> physical colour# conversion table.
+ *	AYM 1998-11-29
+ */
+
+
+#include "colour.h"
+
+
+extern pcolour_t *game_colour;  // Pixel values for the DOOM_COLOURS game clrs.
+extern int colour0;		// Game colour to which g. colour 0 is remapped
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/gcolour3.cc	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,62 @@
+/*
+ *	gcolour3.cc
+ *	AYM 2000-04-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 "colour.h"
+#include "gcolour3.h"
+
+
+Game_colour_24 game_colour_24;
+
+
+void Game_colour_24::refresh (const pcolour_t *game_colour, bool big_endian)
+{
+  if (pv_table == 0)
+    pv_table = new pv24_t[DOOM_COLOURS];
+
+  if (big_endian)
+  {
+    for (size_t n = 0; n < DOOM_COLOURS; n++)
+    {
+      pv_table[n][0] = game_colour[n] / 0x10000;
+      pv_table[n][1] = game_colour[n] / 0x100;
+      pv_table[n][2] = game_colour[n];
+    }
+  }
+  else
+  {
+    for (size_t n = 0; n < DOOM_COLOURS; n++)
+    {
+      pv_table[n][0] = game_colour[n];
+      pv_table[n][1] = game_colour[n] / 0x100;
+      pv_table[n][2] = game_colour[n] / 0x10000;
+    }
+  }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/gcolour3.h	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,79 @@
+/*
+ *	gcolour3.h
+ *	AYM 2000-04-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.
+*/
+
+
+#ifndef YH_GCOLOUR3  /* DO NOT INSERT ANYTHING BEFORE THIS LINE */
+#define YH_GCOLOUR3
+
+
+#include "colour.h"
+
+
+/*
+ *	Game_colour_24 - convert game colours to pixel values
+ *	
+ *	This class is used to speed up displaying of images on
+ *	visuals where bits_per_pixel is 24.
+ *
+ *	Game_colour_24::lut() returns a pointer to a const table
+ *	that is similar to game_colour[] except that it is
+ *	optimized toward the needs of display_img() :
+ *	each member can be readily copied into the XImage buffer
+ *	(this is not true of game_colour[], at least not if the
+ *	client is big-endian or does not have the same
+ *	endianness as the server).
+ *
+ *	There is exactly 1 instance of this class (global). It's
+ *	refreshed in InitGfx() and used in display_img().
+ *	To avoid wasting memory when it's not needed (when the
+ *	depth is != 24), the array is allocated upon refresh and
+ *	refresh() is only called when the depth is == 24.
+ */
+
+
+typedef u8 pv24_t[3];  // A 24-bit pixel value
+
+
+class Game_colour_24
+{
+  public :
+    Game_colour_24 () { pv_table = 0; }
+    ~Game_colour_24 () { if (pv_table) delete[] pv_table; }
+    // Create/refresh the table
+    void refresh (const pcolour_t *game_colour, const bool big_endian);
+    // Return a pointer on an array of pv24_t[DOOM_COLOURS]
+    const pv24_t *lut () { return pv_table; }
+  private :
+    pv24_t *pv_table;
+};
+
+
+extern Game_colour_24 game_colour_24;
+
+
+#endif  /* DO NOT ADD ANYTHING AFTER THIS LINE */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/geom.cc	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,57 @@
+/*
+ *	geom.c
+ *	Geometric stuff
+ *	AYM 1998-08-15
+ */
+
+
+/*
+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 <math.h>
+
+
+/*
+   translate (dx, dy) into an integer angle value (0-65535)
+*/
+
+unsigned ComputeAngle (int dx, int dy)
+{
+return (unsigned) (atan2 ((double) dy, (double) dx) * 10430.37835 + 0.5);
+}
+
+
+
+/*
+   compute the distance from (0, 0) to (dx, dy)
+*/
+
+unsigned ComputeDist (int dx, int dy)
+{
+return (unsigned) (hypot ((double) dx, (double) dy) + 0.5);
+}
+
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/gfx.cc	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,1728 @@
+/*
+ *	gfx.cc
+ *	Graphics routines.
+ *	BW & RQ sometime in 1993 or 1994.
+ */
+
+
+/*
+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 <math.h>
+#ifdef Y_X11
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#endif
+#include "acolours.h"
+#include "gcolour1.h"
+#include "gcolour2.h"
+#include "gcolour3.h"
+#include "gfx.h"
+#include "levels.h"  /* Level */
+#include "x11.h"
+
+#ifdef Y_DOS
+#include <direct.h>
+#endif
+
+
+
+// If your graphics driver doesn't like circles, draw squares instead
+#if defined NO_CIRCLES && defined Y_BGI
+#define circle (x, y, r)	line (x - r, y - r, x - r, y + r); \
+				line (x - r, y + r, x + r, y + r); \
+				line (x + r, y + r, x + r, y - r); \
+				line (x + r, y - r, x - r, y - r)
+#endif  /* NO_CIRCLES */
+
+/* Parameters set by the command line args and config file */
+const char *BGIDriver = "VESA";	// BGI: default extended BGI driver
+bool  CirrusCursor = false;	// use HW cursor on Cirrus Logic VGA cards
+bool  FakeCursor = false;	// use a "fake" mouse cursor
+const char *font_name = NULL;	// X: the name of the font to load
+Win_dim initial_window_width ("90%");	// X: the name says it all
+Win_dim initial_window_height ("90%");	// X: the name says it all
+int   no_pixmap;		// X: use no pixmap -- direct window output
+int   VideoMode = 2;		// BGI: default video mode for VESA cards
+
+/* Global variables */
+int GfxMode = 0;	// graphics mode number, or 0 for text
+			// 1 = 320x200, 2 = 640x480, 3 = 800x600, 4 = 1kx768
+			// positive = 16 colors, negative = 256 colors
+int OrigX;		// Map X-coord of centre of screen/window
+int OrigY;		// Map Y-coord of centre of screen/window
+float Scale;		// the scale value
+int ScrMaxX;		// Maximum display X-coord of screen/window
+int ScrMaxY;		// Maximum display Y-coord of screen/window
+int ScrCenterX;		// Display X-coord of centre of screen/window
+int ScrCenterY;		// Display Y-coord of centre of screen/window
+unsigned FONTH;
+unsigned FONTW;
+int font_xofs;
+int font_yofs;
+
+
+#ifdef Y_X11
+Display *dpy;		// The X display
+int      scn;		// The X screen number
+Colormap cmap = 0;	// The X colormap
+GC       gc;		// Default GC as set by set_colour(), SetDrawingMode()
+                        // and SetLineThickness()
+GC       pixmap_gc;	// The GC used to clear the pixmap
+Window   win;		// The X window
+Pixmap   pixmap;	// The X pixmap (if any)
+Drawable drw;		// Points to either <win> or <pixmap>
+int      drw_mods;	// Number of modifications to drw since last call to
+			// update_display(). Number of modifications to drw
+			// plus 1 since last call to ClearScreen().
+Visual  *win_vis;	// The visual for win */
+xpv_t    win_r_mask;	// The RGB masks for win's visual */
+xpv_t    win_g_mask;
+xpv_t    win_b_mask;
+int      win_r_bits;	// The RGB masks' respective lengths */
+int      win_g_bits;
+int      win_b_bits;
+int      win_r_ofs;	// The RGB masks' respective offsets relative to b0 */
+int      win_g_ofs;
+int      win_b_ofs;
+int      win_ncolours;	// The number of possible colours for win's visual.
+			// If win_vis_class is TrueColor or DirectColor,
+			// it's the number of bits in the biggest subfield.
+int      win_vis_class;	// The class of win's visual
+VisualID win_vis_id;	// The ID of win's visual
+int      win_depth;	// The depth of win in bits
+int      x_server_big_endian = 0;	// Is the X server big endian ?
+int      ximage_bpp;	// Number of bytes per pixels in XImages
+int      ximage_quantum;// Pad XImages lines to a multiple of that many bytes
+static pcolour_t *app_colour = 0;	// Pixel values for the app. colours
+static int DrawingMode    = 0;		// 0 = copy, 1 = xor
+static int LineThickness  = 0;		// 0 = thin, 1 = thick
+int      text_dot         = 0;		// DrawScreenText() debug flag
+#endif
+static acolour_t colour_stack[4];
+static int       colour_stack_pointer = 0;
+static Font      font_xfont;
+static bool      default_font = true;
+
+#if defined Y_BGI && defined CIRRUS_PATCH
+char mp[256];
+char HWCursor[] =
+{
+  0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,
+  0x30, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00,
+  0x1F, 0x00, 0x00, 0x00, 0x1F, 0xC0, 0x00, 0x00,
+  0x0F, 0xF0, 0x00, 0x00, 0x0F, 0xE0, 0x00, 0x00,
+  0x07, 0xC0, 0x00, 0x00, 0x07, 0xE0, 0x00, 0x00,
+  0x03, 0x70, 0x00, 0x00, 0x02, 0x38, 0x00, 0x00,
+  0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x3F, 0xFF, 0xFF, 0xFF, 0x0F, 0xFF, 0xFF, 0xFF,
+  0x83, 0xFF, 0xFF, 0xFF, 0x80, 0xFF, 0xFF, 0xFF,
+  0xC0, 0x3F, 0xFF, 0xFF, 0xC0, 0x0F, 0xFF, 0xFF,
+  0xE0, 0x07, 0xFF, 0xFF, 0xE0, 0x0F, 0xFF, 0xFF,
+  0xF0, 0x1F, 0xFF, 0xFF, 0xF0, 0x0F, 0xFF, 0xFF,
+  0xF8, 0x07, 0xFF, 0xFF, 0xF8, 0x83, 0xFF, 0xFF,
+  0xFD, 0xC7, 0xFF, 0xFF, 0xFF, 0xEF, 0xFF, 0xFF,
+  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
+};
+#endif  /* Y_BGI && CIRRUS_PATCH */
+
+
+/*
+ *	Prototypes
+ */
+#ifdef Y_BGI
+static int cooked_installuserdriver (const char far *__name,
+                             int huge (*detect)(void));
+#endif
+
+/*
+ *	InitGfx - initialize the graphics display
+ *
+ *	Return 0 on success, non-zero on failure
+ */
+int InitGfx (void)
+{
+  // Initialization is in fact not necessary
+  int width;
+  int height;
+
+#if defined Y_BGI
+  static bool firsttime = true;
+  static int  gdriver;
+  static int  gmode;
+  int         errorcode = grNoInitGraph;
+
+  verbmsg ("Switching to graphics mode...\n");
+#if defined Y_BGI && defined CIRRUS_PATCH
+  if (CirrusCursor)
+    SetHWCursorMap (HWCursor);
+#endif  /* Y_BGI && CIRRUS_PATCH */
+  if (firsttime)
+  {
+    if (VideoMode > 0)
+    {
+      gdriver = cooked_installuserdriver (BGIDriver, NULL);
+      gmode = VideoMode;
+      initgraph (&gdriver, &gmode, install_dir);
+      errorcode = graphresult ();
+    }
+    if (errorcode != grOk)
+    {
+      gdriver = VGA;
+      gmode = VGAHI;
+    }
+  }
+  if (gdriver == VGA || !firsttime)
+  {
+    initgraph (&gdriver, &gmode, install_dir);
+    errorcode = graphresult ();
+    if (errorcode != grOk)
+      fatal_error ("graphics error: %s", grapherrormsg (errorcode));
+  }
+  if (gdriver == VGA)
+    GfxMode = 2;  // 640x480x16
+  else
+  {
+    GfxMode = -gmode;  // 640x480x256, 800x600x256, or 1024x768x256
+    SetDoomPalette (0);
+  }
+  verbmsg ("GfxMode=%d\n", GfxMode);
+  setlinestyle (0, 0, 1);
+  setbkcolor (TranslateToDoomColor (BLACK));
+  settextstyle (0, 0, 1);
+  firsttime = false;
+  width = getmaxx () + 1;
+  height = getmaxy () + 1;
+
+#elif defined Y_X11
+
+  /*
+   *	Open display and get screen number
+   */
+  dpy = XOpenDisplay (0);
+  if (! dpy)
+  {
+    err ("Can't open display");
+    return 1;
+  }
+  scn = DefaultScreen (dpy);
+  {
+    verbmsg ("X: server endianness: ");
+    int r = ImageByteOrder (dpy);
+    if (r == LSBFirst)
+    {
+      verbmsg ("little-endian\n");
+      x_server_big_endian = 0;
+    }
+    else if (r == MSBFirst)
+    {
+      verbmsg ("big-endian\n");
+      x_server_big_endian = 1;
+    }
+    else					// Can't happen
+    {
+      verbmsg ("unknown\n");
+      warn ("don't understand X server's endianness code %d\n", r);
+      warn ("assuming same endianness as CPU.\n");
+      x_server_big_endian = cpu_big_endian;
+    }
+  }
+  int screen_width  = DisplayWidth  (dpy, scn);
+  int screen_height = DisplayHeight (dpy, scn);
+  // On QNX 6, XFree returns silly values. Use a plausible default instead.
+  if (screen_width == 16383 && screen_height == 16383)
+  {
+    warn ("QNX XFree bug detected (width %d, height %d)\n",
+	screen_width, screen_height);
+    screen_width  = 1024;
+    screen_height = 768;
+  }
+
+
+  /*
+   *	Create the window
+   */
+  width  = initial_window_width.pixels  (screen_width);
+  height = initial_window_height.pixels (screen_height);
+  win = XCreateSimpleWindow (dpy, DefaultRootWindow (dpy),
+    10, 10, width, height, 0, 0, 0);
+  //win = DefaultRootWindow (dpy);
+  {
+    XWindowAttributes wa;
+    XVisualInfo model;
+    XVisualInfo *vis_info;
+    int nvisuals;
+
+    XGetWindowAttributes (dpy, win, &wa);
+    win_vis   = wa.visual;
+    win_depth = wa.depth;
+    verbmsg ("X: window depth: %d b\n", win_depth);
+
+    /*
+     *	Retrieve info regarding win's visual
+     */
+    model.visualid = XVisualIDFromVisual (win_vis);
+    vis_info = XGetVisualInfo (dpy, VisualIDMask, &model, &nvisuals);
+    if (! vis_info)
+      fatal_error ("XGetVisualInfo returned NULL for ID %d", model.visualid);
+    if (nvisuals != 1)
+      fatal_error ("XGetVisualInfo returned %d visuals", nvisuals);
+    if (vis_info->depth != win_depth)
+      fatal_error ("Visual depth %d <> win depth %d", vis_info->depth, win_depth);
+    win_vis_id    = vis_info->visualid;
+#if defined _cplusplus || defined __cplusplus
+    win_vis_class = vis_info->c_class;
+#elif
+    win_vis_class = vis_info->class;
+#endif
+    win_ncolours  = vis_info->colormap_size;
+    win_r_mask    = vis_info->red_mask;
+    win_g_mask    = vis_info->green_mask;
+    win_b_mask    = vis_info->blue_mask;
+    XFree (vis_info);
+    verbmsg ("X: visual: id %xh, class ", (unsigned) win_vis_id);
+    if (win_vis_class == PseudoColor)
+      verbmsg ("PseudoColor");
+    else if (win_vis_class == TrueColor)
+      verbmsg ("TrueColor");
+    else if (win_vis_class == DirectColor)
+      verbmsg ("DirectColor");
+    else if (win_vis_class == StaticColor)
+      verbmsg ("StaticColor");
+    else if (win_vis_class == GrayScale)
+      verbmsg ("GrayScale");
+    else if (win_vis_class == StaticGray)
+      verbmsg ("StaticGray");
+    else
+      verbmsg ("unknown (%d)", win_vis_class);
+    verbmsg (", colours %d, masks %08lX %08lX %08lX\n",
+      win_ncolours, win_r_mask, win_g_mask, win_b_mask);
+
+    // Compute win_[rgb]_bits and win_[rgb]_ofs
+    /* FIXME can enter infinite loop if MSb of either mask is set
+       and >> sign extends. */
+    if (win_r_mask)
+    {
+      xpv_t mask;
+      for (mask = win_r_mask, win_r_ofs = 0; ! (mask & 1); mask >>= 1)
+	 win_r_ofs++;
+      for (win_r_bits = 0; mask & 1; mask >>= 1)
+	 win_r_bits++;
+    }
+    if (win_g_mask)
+    {
+      xpv_t mask;
+      for (mask = win_g_mask, win_g_ofs = 0; ! (mask & 1); mask >>= 1)
+	 win_g_ofs++;
+      for (win_g_bits = 0; mask & 1; mask >>= 1)
+	 win_g_bits++;
+    }
+    if (win_b_mask)
+    {
+      xpv_t mask;
+      for (mask = win_b_mask, win_b_ofs = 0; ! (mask & 1); mask >>= 1)
+	 win_b_ofs++;
+      for (win_b_bits = 0; mask & 1; mask >>= 1)
+	 win_b_bits++;
+    }
+    verbmsg ("X: visual: "
+	     "r_ofs %d, r_bits %d, ", win_r_ofs, win_r_bits);
+    verbmsg ("g_ofs %d, g_bits %d, ", win_g_ofs, win_g_bits);
+    verbmsg ("b_ofs %d, b_bits %d\n", win_b_ofs, win_b_bits);
+  }
+
+  /*
+   *	Get info relevant to XImages
+   */
+  ximage_bpp     = 0;
+  ximage_quantum = 0;
+  {
+    int nformats = 0;
+    XPixmapFormatValues *format = XListPixmapFormats (dpy, &nformats);
+    if (format == 0 || nformats < 1)
+    {
+      warn ("XListPixmapFormats() trouble (ret=%p, n=%d).\n", format, nformats);
+      goto ximage_done;
+    }
+    /* Pick the best possible pixmap format. Prefer one that has the
+       same depth as the drawable, as it is likely to be the fastest
+       one. Should there be several formats that satisfy that
+       requirement (I don't think that ever happens), prefer the one
+       where the line quantum is equal to the number of bits per
+       pixel, as that is easier to work with. */
+    {
+      const XPixmapFormatValues *best = 0;
+      for (int n = 0; n < nformats; n++)
+      {
+	const XPixmapFormatValues *current = format + n;
+	verbmsg ("X: pixmap format:"
+	    " #%d, depth %2d, bits_per_pixel %2d, scanline_pad %2d\n",
+	    n, current->depth, current->bits_per_pixel, current->scanline_pad);
+	if (best == 0)
+	{
+	  best = current;
+	  continue;
+	}
+	int cgoodness = 2 * (current->depth == win_depth)
+		      + 1 * (current->scanline_pad == current->bits_per_pixel);
+	int bgoodness = 2 * (best->depth == win_depth)
+		      + 1 * (best->scanline_pad == best->bits_per_pixel);
+	if (cgoodness > bgoodness)
+	  best = current;
+      }
+      verbmsg ("X: pixmap format: best is #%d\n", int (best - format));
+      if (best != 0)
+      {
+	int bits_per_pixel = best->bits_per_pixel;
+	if (bits_per_pixel % 8)  // Paranoia
+	 {
+	   round_up (bits_per_pixel, 8);
+	   warn ("XImage format has bad bits_per_pixel %d. Rounding up to %d.\n",
+	      best->bits_per_pixel, bits_per_pixel);
+	 }
+	int scanline_pad = best->scanline_pad;
+	if (best->scanline_pad % 8)  // Paranoia
+	 {
+	   round_up (scanline_pad, 8);
+	   warn ("XImage format has bad scanline_pad %d. Rounding up to %d.\n",
+	      best->scanline_pad, scanline_pad);
+	 }
+	ximage_bpp     = bits_per_pixel / 8;
+	ximage_quantum = scanline_pad   / 8;
+      }
+    }
+    if (ximage_bpp == 0 || ximage_quantum == 0)
+    {
+      warn ("XListPixmapFormats() returned no suitable formats.\n"); 
+      goto ximage_done;
+    }
+    ximage_done:
+    if (format != 0)
+      XFree (format);
+  }
+  /* Could not obtain authoritative/good values. Warn and guess
+     plausible values. */
+  if (ximage_bpp == 0 || ximage_quantum == 0)
+  {
+    if (ximage_bpp == 0)
+      ximage_bpp = (win_depth + 7) / 8;
+    if (ximage_quantum == 0)
+      ximage_quantum = 4;
+    warn ("guessing format. Images will probably not be displayed correctly\n");
+  }
+  verbmsg ("X: pixmap format: %d B per pixel, %d B quantum.\n",
+    ximage_bpp, ximage_quantum);
+
+  /*
+   *	Further configure the window
+   */
+#if 0
+  {
+    XSetWindowAttributes wa;
+    wa.win_gravity = CenterGravity;
+    XChangeWindowAttributes (dpy, win, CWWinGravity, &wa);
+  }
+#endif
+
+  XStoreName (dpy, win, "Yadex");  // Temporary name -- will be overwritten
+  XSelectInput (dpy, win,
+    KeyPressMask | KeyReleaseMask
+    | ButtonPressMask | ButtonReleaseMask
+    | PointerMotionMask
+    | EnterWindowMask | LeaveWindowMask
+    | ExposureMask
+    | StructureNotifyMask);
+
+  /*
+   *	Possibly load and query the font
+   */
+  {
+    XFontStruct *xqf;
+
+    // Load the font or use the default font.
+    default_font = true;
+    if (font_name != NULL)
+    {
+      x_catch_on ();  // Catch errors in XLoadFont()
+      font_xfont = XLoadFont (dpy, font_name);
+      if (const char *err_msg = x_error ())
+      {
+	warn ("can't load font \"%s\" (%s).\n", font_name, err_msg);
+	warn ("using default font instead.\n");
+      }
+      else
+	 default_font = false;
+      x_catch_off ();
+    }
+
+    // Query the font we'll use for FONTW, FONTH and FONTYOFS.
+    xqf = XQueryFont (dpy,
+      default_font ? XGContextFromGC (DefaultGC (dpy, scn)) : font_xfont);
+    if (xqf->direction != FontLeftToRight)
+      warn ("this font is not left-to-right !\n");
+    if (xqf->min_byte1 != 0 || xqf->max_byte1 != 0)
+      warn ("this is not a single-byte font !\n");
+    if (xqf->min_char_or_byte2 > 32 || xqf->max_char_or_byte2 < 126)
+      warn ("this font does not support the ASCII character set !\n");
+    if (xqf->min_bounds.width != xqf->max_bounds.width)
+      warn ("this is not a fixed-width font !\n");
+    FONTW     = xqf->max_bounds.width;
+    FONTH     = xqf->ascent + xqf->descent;
+    font_xofs = xqf->min_bounds.lbearing;
+    font_yofs = xqf->max_bounds.ascent;
+    XFreeFontInfo (NULL, xqf, 1);
+    verbmsg ("X: font: metrics: %dx%d, xofs %d, yofs %d\n",
+      FONTW, FONTH, font_xofs, font_yofs);
+  }
+
+  /*
+   *	Get/create the colormap
+   *	and allocate the colours.
+   */
+  if (win_vis_class == PseudoColor)
+  {
+    verbmsg ("X: running on PseudoColor visual, using private Colormap\n");
+    cmap = XCreateColormap (dpy, win, win_vis, AllocNone);
+  }
+  else
+    cmap = DefaultColormap (dpy, scn);
+
+  XSetWindowColormap (dpy, win, cmap);
+  game_colour = alloc_game_colours (0);
+  app_colour = commit_app_colours ();
+  if (win_depth == 24)
+    game_colour_24.refresh (game_colour, x_server_big_endian);
+
+  /*
+   *	Create the GC
+   */
+  {
+    XGCValues gcv;
+    unsigned long mask;
+
+    mask = GCForeground | GCFunction | GCLineWidth;
+    if (! default_font)
+    {
+      mask |= GCFont;
+      gcv.font = font_xfont;
+    }
+    gcv.foreground = app_colour[0];  // Default colour
+    gcv.line_width = 0;
+    gcv.function   = GXcopy;
+    gc = XCreateGC (dpy, win, mask, &gcv);
+    if (gc == 0)
+      fatal_error ("XCreateGC() returned NULL");
+  }
+
+
+  /*
+   *	More stuff
+   */
+  XSetWindowBackground (dpy, win, app_colour[0]);
+  XMapWindow (dpy, win);
+
+  // Unless no_pixmap is set, create the pixmap and its own pet GC.
+  if (no_pixmap)
+    drw = win;
+  else
+  {
+    XGCValues gcv;
+
+    pixmap = XCreatePixmap (dpy, win, width, height, win_depth);
+    gcv.foreground = app_colour[0];
+    gcv.graphics_exposures = False;  // We don't want NoExpose events
+    pixmap_gc = XCreateGC (dpy, pixmap, GCForeground | GCGraphicsExposures,
+	&gcv);
+    drw = win;
+    drw_mods = 0;  // Force display the first time
+  }
+  XSync (dpy, False);
+  GfxMode = - VideoMode;
+#endif
+
+  SetWindowSize (width, height);
+  return 0;
+}
+
+
+/*
+ *	TermGfx - terminate the graphics display
+ */
+void TermGfx ()
+{
+  verbmsg ("TermGfx: GfxMode=%d\n", GfxMode);
+  if (GfxMode)
+  {
+#if defined Y_BGI
+    closegraph ();
+#elif defined Y_X11
+    int r;
+
+    if (! no_pixmap)
+    {
+      XFreePixmap (dpy, pixmap);
+      XFreeGC     (dpy, pixmap_gc);
+    }
+    r = XDestroyWindow (dpy, win);
+    verbmsg ("X: XDestroyWindow returned %d\n", r);
+    free_game_colours (game_colour);
+    game_colour = 0;
+    uncommit_app_colours (app_colour);
+    app_colour = 0;
+    if (cmap != DefaultColormap (dpy, scn))
+    {
+      verbmsg ("X: freeing Colormap\n");
+      XFreeColormap  (dpy, cmap);
+    }
+    if (! default_font)
+    {
+      verbmsg ("X: unloading font\n");
+      XUnloadFont (dpy, font_xfont);
+    }
+    XFreeGC (dpy, gc);
+    gc = 0;
+    // FIXME there is surely more to do...
+    XCloseDisplay (dpy);
+#endif
+    GfxMode = 0;
+  }
+}
+
+
+/*
+ *	SetWindowSize - set the size of the edit window
+ */
+void SetWindowSize (int width, int height)
+{
+  // Am I called uselessly ?
+  if (width == ScrMaxX + 1 && height == ScrMaxY + 1)
+    return;
+
+  ScrMaxX = width - 1;
+  ScrMaxY = height - 1;
+  ScrCenterX = ScrMaxX / 2;
+  ScrCenterY = ScrMaxY / 2;
+#ifdef Y_X11
+  // Replace the old pixmap by another of the new size
+  if (! no_pixmap)
+  {
+    XFreePixmap (dpy, pixmap);
+    pixmap = XCreatePixmap (dpy, win, width, height, win_depth);
+    drw = pixmap;
+  }
+#endif
+}
+
+
+/*
+ *	SwitchToVGA256 - switch from VGA 16 colours to VGA 256 colours
+ *
+ *	This function does something only in the BGI version and
+ *	if the current mode is 16 colours (typically because the
+ *	video card is a plain VGA one (as opposed to an SVGA
+ *	one) so the only 256-colour mode is 320x200).
+ *
+ *	If compiled with Y_X11, this function is a no-op.
+ */
+void SwitchToVGA256 (void)
+{
+#if defined Y_X11
+  return;
+#elif defined Y_BGI
+  static int gdriver = -1;
+  int gmode, errorcode;
+
+  if (GfxMode > 0 && gdriver != VGA) /* if 16 colors and not failed before */
+  {
+  if (gdriver == -1)
+  {
+    gdriver = cooked_installuserdriver ("VGA256", NULL);
+    errorcode = graphresult ();
+  }
+  HideMousePointer ();
+  closegraph ();
+  gmode = 0;
+  initgraph (&gdriver, &gmode, install_dir);
+  errorcode = graphresult ();
+  if (errorcode != grOk)
+  {
+    // Failed for 256 colors - back to 16 colors
+    gdriver = VGA;
+    gmode = VGAHI;
+    initgraph (&gdriver, &gmode, install_dir);
+    errorcode = graphresult ();
+  }
+  if (errorcode != grOk)  // Shouldn't happen
+    fatal_error ("graphics error: %s", grapherrormsg (errorcode));
+  ShowMousePointer ();
+  GfxMode = -1;  // 320x200x256
+  SetDoomPalette (0);
+  ScrMaxX = getmaxx ();
+  ScrMaxY = getmaxy ();
+  ScrCenterX = ScrMaxX / 2;
+  ScrCenterY = ScrMaxY / 2;
+  }
+#endif
+}
+
+
+/*
+ *	SwitchToVGA16 -  switch from VGA 256 colours to VGA 16 colours
+ *
+ *	See comments for SwitchToVGA256().
+ */
+void SwitchToVGA16 (void)
+{
+#if defined Y_X11
+  return;
+#elif defined Y_BGI
+  int gdriver, gmode, errorcode;
+
+  if (GfxMode == -1)  // Switch only if we are in 320x200x256 colors
+  {
+    HideMousePointer ();
+    closegraph ();
+    gdriver = VGA;
+    gmode = VGAHI;
+    initgraph (&gdriver, &gmode, install_dir);
+    errorcode = graphresult ();
+    if (errorcode != grOk)  // Shouldn't happen
+      fatal_error ("graphics error: %s", grapherrormsg (errorcode));
+    ShowMousePointer ();
+    GfxMode = 2;  // 640x480x16
+    ScrMaxX = getmaxx ();
+    ScrMaxY = getmaxy ();
+    ScrCenterX = ScrMaxX / 2;
+    ScrCenterY = ScrMaxY / 2;
+  }
+#else
+  ;
+#endif
+}
+
+
+/*
+ *	ClearScreen - clear the screen
+ */
+void ClearScreen ()
+{
+#if defined Y_BGI
+  cleardevice ();
+#elif defined Y_X11
+  if (no_pixmap)
+    XClearWindow (dpy, win);
+  else
+  {
+    XFillRectangle (dpy, pixmap, pixmap_gc, 0, 0, ScrMaxX + 1, ScrMaxY + 1);
+    drw = pixmap;  // Redisplaying from scratch so let's use the pixmap
+  }
+#else
+  ;
+#endif
+}
+
+
+/*
+ *	update_display - update the physical display
+ *
+ *	Make sure the physical bitmap display (the X window)
+ *	is up to date WRT the logical bitmap display (the X
+ *	pixmap).
+ *
+ *	If <drw> == <win>, it means that only partial
+ *	changes were made and that they were made directly on
+ *	the window, not on the pixmap so no need to copy the
+ *	pixmap onto the window.
+ */
+void update_display ()
+{
+#if defined Y_BGI
+  ;  // Nothing ; with BGI, screen output is synchronous
+#elif defined Y_X11
+  //if (drw_mods == 0)  // Nothing to do, display is already up to date
+  //   return;
+  //printf (" [");
+  //fflush (stdout);
+  if (! no_pixmap && drw == pixmap)
+  {
+    //putchar ('*');
+    XCopyArea (dpy, pixmap, win, pixmap_gc, 0, 0, ScrMaxX+1, ScrMaxY+1, 0, 0);
+  }
+  XFlush (dpy);
+  //printf ("] ");
+  //fflush (stdout);
+  drw_mods = 0;
+  drw = win;  // If they don't like it, they can call ClearScreen() [HHOS]
+#else
+  ;
+#endif
+}
+
+
+/*
+ *	force_window_not_pixmap - force graphic ops to use window
+ *
+ *	Redirect graphic output to window, not pixmap. Used only
+ *	in yadex.cc, before calling the sprite viewer.
+ *
+ *	FIXME this is not a clean way to do things.
+ */
+void force_window_not_pixmap ()
+{
+  drw = win;
+}
+
+
+/*
+ *	set_pcolour - set the current drawing colour
+ *
+ *	<colour> must be an physical colour number (a.k.a. pixel value).
+ */
+void set_pcolour (pcolour_t colour)
+{
+  XSetForeground (dpy, gc, (xpv_t) colour);
+}
+
+
+// Last application colour set by set_colour()
+static acolour_t current_acolour = 0;
+#ifdef Y_BGI
+static int current_bgicolour = 0;
+#endif
+
+
+/*
+ *	get_colour - get the current drawing colour
+ */
+acolour_t get_colour ()
+{
+  return current_acolour;
+}
+
+
+/*
+ *	set_colour - set the current drawing colour
+ *
+ *	<colour> must be an application colour number.
+ */
+void set_colour (acolour_t colour)
+{
+#if defined Y_BGI
+  if (colour != current_acolour)
+  {
+    current_acolour = colour;
+    current_bgicolour = (GfxMode < 0) ? TranslateToDoomColor (colour) : colour;
+    setcolor (current_bgicolour);
+  }
+#elif defined Y_X11
+  if (colour != current_acolour)
+  {
+    current_acolour = colour;
+    XSetForeground (dpy, gc, app_colour[colour]);
+  }
+#endif
+}
+
+
+/*
+ *	push_colour - push a colour into the colour stack
+ *
+ *	Like set_colour() except that it will only last until
+ *	the next call to pop_colour().
+ */
+void push_colour (acolour_t colour)
+{
+  if (colour_stack_pointer >= (int) (sizeof colour_stack / sizeof *colour_stack))
+  {
+    nf_bug ("Colour stack overflow");
+    return;
+  }
+  colour_stack[colour_stack_pointer] = current_acolour;
+  colour_stack_pointer++;
+  set_colour (colour);
+}
+
+
+/*
+ *	pop_colour - pop the colour stack
+ *
+ *	Cancel the effect of the last call to push_colour().
+ */
+void pop_colour (void)
+{
+  if (colour_stack_pointer < 1)
+  {
+    nf_bug ("Colour stack underflow");
+    return;
+  }
+  colour_stack_pointer--;
+  set_colour (colour_stack[colour_stack_pointer]);
+}
+
+
+/*
+ *	SetLineThickness - set the line style (thin or thick)
+ */
+void SetLineThickness (int thick)
+{
+#if defined Y_BGI
+  setlinestyle (SOLID_LINE, 0, thick ? THICK_WIDTH : NORM_WIDTH);
+#elif defined Y_X11
+  if (!! thick != LineThickness)
+  {
+    LineThickness = !! thick;
+    XGCValues gcv;
+    gcv.line_width = LineThickness ? 3 : (DrawingMode ? 1 : 0);
+    // ^ It's important to use a line_width of 1 when in xor mode.
+    // See note (1) in the hacker's guide.
+    XChangeGC (dpy, gc, GCLineWidth, &gcv);
+  }
+#endif
+}
+
+
+/*
+ *	SetDrawingMode - set the drawing mode (copy or xor)
+ */
+void SetDrawingMode (int _xor)
+{
+#if defined Y_BGI
+  setwritemode (_xor ? XOR_PUT : COPY_PUT);
+#elif defined Y_X11
+  if (!! _xor != DrawingMode)
+  {
+    DrawingMode = !! _xor;
+    XGCValues gcv;
+    gcv.function = DrawingMode ? GXxor : GXcopy;
+    gcv.line_width = LineThickness ? 3 : (DrawingMode ? 1 : 0);
+    // ^ It's important to use a line_width of 1 when in xor mode.
+    // See note (1) in the hacker's guide.
+    XChangeGC (dpy, gc, GCFunction | GCLineWidth, &gcv);
+  }
+#endif
+}
+
+
+/*
+ *	draw_point - draw a point at display coordinates
+ *
+ *	The point is drawn at display coordinates (<x>, <y>).
+ */
+void draw_point (int x, int y)
+{
+#if defined Y_BGI
+  putpixel (x, y, current_bgicolour);
+#elif defined Y_X11
+  XDrawPoint (dpy, drw, gc, x, y);
+#endif
+}
+
+
+/*
+ *	draw_map_point - draw a point at map coordinates
+ *
+ *	The point is drawn at map coordinates (<mapx>, <mapy>)
+ */
+void draw_map_point (int mapx, int mapy)
+{
+#if defined Y_BGI
+  putpixel (SCREENX (mapx), SCREENY (mapy), current_bgicolour);
+#elif defined Y_X11
+  XDrawPoint (dpy, drw, gc, SCREENX (mapx), SCREENY (mapy));
+  drw_mods++;
+#endif
+}
+
+
+/*
+ *	DrawMapLine - draw a line on the screen from map coords
+ */
+void DrawMapLine (int mapx1, int mapy1, int mapx2, int mapy2)
+{
+#if defined Y_BGI
+  line (SCREENX (mapx1), SCREENY (mapy1), SCREENX (mapx2), SCREENY (mapy2));
+#elif defined Y_X11
+  XDrawLine (dpy, drw, gc, SCREENX (mapx1), SCREENY (mapy1),
+			   SCREENX (mapx2), SCREENY (mapy2));
+  drw_mods++;
+#endif
+}
+
+
+/*
+ *	DrawMapCircle - draw a circle on the screen from map coords
+ */
+void DrawMapCircle (int mapx, int mapy, int mapradius)
+{
+#if defined Y_BGI
+  circle (SCREENX (mapx), SCREENY (mapy), (int) (mapradius * Scale));
+#elif defined Y_X11
+  XDrawArc (dpy, drw, gc, SCREENX (mapx - mapradius), SCREENY (mapy + mapradius),
+    (unsigned int) (2 * mapradius * Scale),
+    (unsigned int) (2 * mapradius * Scale), 0, 360*64);
+  drw_mods++;
+#endif
+}
+
+
+
+/*
+ *	DrawMapVector - draw an arrow on the screen from map coords
+ */
+void DrawMapVector (int mapx1, int mapy1, int mapx2, int mapy2)
+{
+  int    scrx1   = SCREENX (mapx1);
+  int    scry1   = SCREENY (mapy1);
+  int    scrx2   = SCREENX (mapx2);
+  int    scry2   = SCREENY (mapy2);
+  double r       = hypot ((double) (scrx1 - scrx2), (double) (scry1 - scry2));
+#if 0
+  /* AYM 19980216 to avoid getting huge arrowheads when zooming in */
+  int    scrXoff = (r >= 1.0) ? (int) ((scrx1 - scrx2) * 8.0 / r * (Scale < 1 ? Scale : 1)) : 0;
+  int    scrYoff = (r >= 1.0) ? (int) ((scry1 - scry2) * 8.0 / r * (Scale < 1 ? Scale : 1)) : 0;
+#else
+  int    scrXoff = (r >= 1.0) ? (int) ((scrx1 - scrx2) * 8.0 / r * (Scale / 2)) : 0;
+  int    scrYoff = (r >= 1.0) ? (int) ((scry1 - scry2) * 8.0 / r * (Scale / 2)) : 0;
+#endif
+
+#if defined Y_BGI
+  line (scrx1, scry1, scrx2, scry2);
+  scrx1 = scrx2 + 2 * scrXoff;
+  scry1 = scry2 + 2 * scrYoff;
+  line (scrx1 - scrYoff, scry1 + scrXoff, scrx2, scry2);
+  line (scrx1 + scrYoff, scry1 - scrXoff, scrx2, scry2);
+#elif defined Y_X11
+  XDrawLine (dpy, drw, gc, scrx1, scry1, scrx2, scry2);
+  scrx1 = scrx2 + 2 * scrXoff;
+  scry1 = scry2 + 2 * scrYoff;
+  XDrawLine (dpy, drw, gc, scrx1 - scrYoff, scry1 + scrXoff, scrx2, scry2);
+  XDrawLine (dpy, drw, gc, scrx1 + scrYoff, scry1 - scrXoff, scrx2, scry2);
+  drw_mods++;
+#endif
+}
+
+
+/*
+ *	DrawMapArrow - draw an arrow on the screen from map coords and angle (0 - 65535)
+ */
+void DrawMapArrow (int mapx1, int mapy1, unsigned angle)
+{
+  int    mapx2   = mapx1 + (int) (50 * cos (angle / 10430.37835));
+  int    mapy2   = mapy1 + (int) (50 * sin (angle / 10430.37835));
+  int    scrx1   = SCREENX (mapx1);
+  int    scry1   = SCREENY (mapy1);
+  int    scrx2   = SCREENX (mapx2);
+  int    scry2   = SCREENY (mapy2);
+  double r       = hypot (scrx1 - scrx2, scry1 - scry2);
+#if 0
+  int    scrXoff = (r >= 1.0) ? (int) ((scrx1 - scrx2) * 8.0 / r * (Scale < 1 ? Scale : 1)) : 0;
+  int    scrYoff = (r >= 1.0) ? (int) ((scry1 - scry2) * 8.0 / r * (Scale < 1 ? Scale : 1)) : 0;
+#else
+  int    scrXoff = (r >= 1.0) ? (int) ((scrx1 - scrx2) * 8.0 / r * (Scale / 2)) : 0;
+  int    scrYoff = (r >= 1.0) ? (int) ((scry1 - scry2) * 8.0 / r * (Scale / 2)) : 0;
+#endif
+
+#if defined Y_BGI
+  line (scrx1, scry1, scrx2, scry2);
+  scrx1 = scrx2 + 2 * scrXoff;
+  scry1 = scry2 + 2 * scrYoff;
+  line (scrx1 - scrYoff, scry1 + scrXoff, scrx2, scry2);
+  line (scrx1 + scrYoff, scry1 - scrXoff, scrx2, scry2);
+#elif defined Y_X11
+  XDrawLine (dpy, drw, gc, scrx1, scry1, scrx2, scry2);
+  scrx1 = scrx2 + 2 * scrXoff;
+  scry1 = scry2 + 2 * scrYoff;
+  XDrawLine (dpy, drw, gc, scrx1 - scrYoff, scry1 + scrXoff, scrx2, scry2);
+  XDrawLine (dpy, drw, gc, scrx1 + scrYoff, scry1 - scrXoff, scrx2, scry2);
+  drw_mods++;
+#endif
+}
+
+
+/*
+ *	DrawScreenLine - draw a line on the screen from screen coords
+ */
+void DrawScreenLine (int Xstart, int Ystart, int Xend, int Yend)
+{
+#if defined Y_BGI
+  line (Xstart, Ystart, Xend, Yend);
+#elif defined Y_X11
+  XDrawLine (dpy, drw, gc, Xstart, Ystart, Xend, Yend);
+  drw_mods++;
+#endif
+}
+
+
+/*
+ *	DrawScreenLineLen - draw a line on the screen
+ */
+void DrawScreenLineLen (int x, int y, int width, int height)
+{
+#if defined Y_BGI
+  line (x, y, x + width - 1, y + height - 1);
+#elif defined Y_X11
+  if (width > 0)
+    width--;
+  else if (width < 0)
+    width++;
+  if (height > 0)
+    height--;
+  else if (height < 0)
+    height++;
+  XDrawLine (dpy, drw, gc, x, y, x + width, y + height);
+  drw_mods++;
+#endif
+}
+
+
+/*
+ *	DrawScreenRect - draw a rectangle
+ *
+ *	Unlike most functions here, the 3rd and 4th parameters
+ *	specify lengths, not coordinates.
+ */
+void DrawScreenRect (int x, int y, int width, int height)
+{
+#if defined Y_BGI
+  rectangle (x, y, x + width - 1, y + height - 1);
+#elif defined Y_X11
+  XDrawRectangle (dpy, drw, gc, x, y, width - 1, height - 1);
+  drw_mods++;
+#endif
+}
+
+
+/*
+ *	DrawScreenBox - draw a filled in box on the screen from screen coords
+ *
+ *	(scrx1, scry1) is the top left corner
+ *	(scrx2, scry2) is the bottom right corner
+ *	If scrx2 < scrx1 or scry2 < scry1, the function does nothing.
+ */
+void DrawScreenBox (int scrx1, int scry1, int scrx2, int scry2)
+{
+  if (scrx2 < scrx1 || scry2 < scry1)
+    return;
+#if defined Y_BGI
+  setfillstyle (1, getcolor ());
+  bar (scrx1, scry1, scrx2, scry2);
+#elif defined Y_X11
+  // FIXME missing gc fill_style
+  XFillRectangle (dpy, drw, gc, scrx1, scry1,
+    scrx2 - scrx1 + 1, scry2 - scry1 + 1);
+  drw_mods++;
+#endif
+}
+
+
+/*
+ *	DrawScreenBoxwh - draw a filled rectangle of width x height pixels
+ *
+ *	(scrx0, scry0) is the top left corner
+ *	(width, height) is the obvious
+ *	If width < 1 or height < 1, does nothing.
+ */
+void DrawScreenBoxwh (int scrx0, int scry0, int width, int height)
+{
+  if (width < 1 || height < 1)
+    return;
+#if defined Y_BGI
+  setfillstyle (1, getcolor ());
+  bar (scrx0, scry0, scrx0 + width - 1, scry0 + height - 1);
+#elif defined Y_X11
+  // FIXME missing gc fill_style
+  XFillRectangle (dpy, drw, gc, scrx0, scry0, width, height);
+  drw_mods++;
+#endif
+}
+
+
+/*
+ *	DrawScreenBox3D - draw a filled-in 3D box on the screen
+ *
+ *	The 3D border is rather wide (BOX_BORDER pixels wide).
+ */
+void DrawScreenBox3D (int scrx1, int scry1, int scrx2, int scry2)
+{
+  DrawScreenBox3DShallow (scrx1, scry1, scrx2, scry2);
+  push_colour (WINBG_DARK);
+#if defined Y_BGI
+  line (scrx1 + 1, scry2 - 1, scrx2 - 1, scry2 - 1);
+  line (scrx2 - 1, scry1 + 1, scrx2 - 1, scry2 - 1);
+#elif defined Y_X11
+  XDrawLine (dpy, drw, gc, scrx1 + 1, scry2 - 1, scrx2 - 1, scry2 - 1);
+  XDrawLine (dpy, drw, gc, scrx2 - 1, scry1 + 1, scrx2 - 1, scry2 - 1);
+#endif
+  set_colour (WINBG_LIGHT);
+#if defined Y_BGI
+  line (scrx1 + 1, scry1 + 1, scrx1 + 1, scry2 - 1);
+  line (scrx1 + 1, scry1 + 1, scrx2 - 1, scry1 + 1);
+#elif defined Y_X11
+  XDrawLine (dpy, drw, gc, scrx1 + 1, scry1 + 1, scrx1 + 1, scry2 - 1);
+  XDrawLine (dpy, drw, gc, scrx1 + 1, scry1 + 1, scrx2 - 1, scry1 + 1);
+  drw_mods++;
+#endif
+  pop_colour ();
+}
+
+
+/*
+ *	DrawScreenBox3DShallow - draw a filled-in 3D box on the screen
+ *
+ *	Same thing as DrawScreenBox3D but shallow (the 3D border
+ *	is NARROW_BORDER pixels wide).
+ */
+void DrawScreenBox3DShallow (int scrx1, int scry1, int scrx2, int scry2)
+{
+#if defined Y_BGI
+  setfillstyle (1, TranslateToDoomColor (LIGHTGREY));
+  bar (scrx1 + 1, scry1 + 1, scrx2 - 1, scry2 - 1);
+  push_colour (WINBG_DARK);
+  line (scrx1, scry2, scrx2, scry2);
+  line (scrx2, scry1, scrx2, scry2);
+  set_colour (WINBG_LIGHT);
+  line (scrx1, scry1, scrx2, scry1);
+  line (scrx1, scry1, scrx1, scry2);
+  pop_colour ();
+
+#elif defined Y_X11
+  push_colour (WINBG);
+  XFillRectangle (dpy, drw, gc, scrx1+1, scry1+1, scrx2-scrx1, scry2-scry1);
+  set_colour (WINBG_DARK);
+  XDrawLine (dpy, drw, gc, scrx1, scry2, scrx2, scry2);
+  XDrawLine (dpy, drw, gc, scrx2, scry1, scrx2, scry2);
+  set_colour (WINBG_LIGHT);
+  XDrawLine (dpy, drw, gc, scrx1, scry1, scrx2, scry1);
+  XDrawLine (dpy, drw, gc, scrx1, scry1, scrx1, scry2);
+  drw_mods++;
+  pop_colour ();
+#endif
+}
+
+
+/*
+ *	draw_box_border - draw the 3D border of a box.
+ *
+ *	(x, y) is the outer top left corner.
+ *	(width, height) are the outer dimensions.
+ *	(thickness) is the thickness of the border in pixels.
+ *	(raised) is zero for depressed, non-zero for raised.
+ */
+void draw_box_border (int x, int y, int width, int height,
+  int thickness, int raised)
+{
+#if defined Y_BGI
+#error "You need to write the BGI version of draw_box_border()"
+#elif defined Y_X11
+  int n;
+  XPoint points[3];
+
+  // We want offsets, not distances
+  width--;
+  height--;
+
+  // Draw the right and bottom edges
+  push_colour (raised ? WINBG_DARK : WINBG_LIGHT);
+  points[0].x = x + width;
+  points[0].y = y;
+  points[1].x = 0;
+  points[1].y = height;
+  points[2].x = -width;
+  points[2].y = 0;
+  for (n = 0; n < thickness; n++)
+  {
+    XDrawLines (dpy, drw, gc, points, 3, CoordModePrevious);
+    points[0].x--;
+    points[0].y++;
+    points[1].y--;
+    points[2].x++;
+  }
+
+  // Draw the left and top edges
+  set_colour (raised ? WINBG_LIGHT : WINBG_DARK);
+  points[0].x = x;
+  points[0].y = y + height;
+  points[1].x = 0;
+  points[1].y = -height;
+  points[2].x = width;
+  points[2].y = 0;
+  for (n = 0; n < thickness; n++)
+  {
+    XDrawLines (dpy, drw, gc, points, 3, CoordModePrevious);
+    points[0].x++;
+    points[0].y--;
+    points[1].y++;
+    points[2].x--;
+  }
+
+  pop_colour ();
+#endif
+}
+
+
+/*
+ *	DrawScreenBoxHollow - draw a hollow 3D box on the screen
+ *
+ *	The 3D border is HOLLOW_BORDER pixels wide.
+ */
+void DrawScreenBoxHollow (int scrx1, int scry1, int scrx2, int scry2, acolour_t colour)
+{
+#if defined Y_BGI
+  setfillstyle (1, TranslateToDoomColor (colour));
+  bar (scrx1 + HOLLOW_BORDER, scry1 + HOLLOW_BORDER,
+       scrx2 - HOLLOW_BORDER, scry2 - HOLLOW_BORDER);
+  push_colour (WINBG_LIGHT);
+  line (scrx1, scry2, scrx2, scry2);
+  line (scrx2, scry1, scrx2, scry2);
+  set_colour (WINBG_DARK);
+  line (scrx1, scry1, scrx2, scry1);
+  line (scrx1, scry1, scrx1, scry2);
+  pop_colour ();
+
+#elif defined Y_X11
+  push_colour (colour);
+  XFillRectangle (dpy, drw, gc,
+      scrx1 + HOLLOW_BORDER, scry1 + HOLLOW_BORDER,
+      scrx2 + 1 - scrx1 - 2 * HOLLOW_BORDER, scry2 + 1 - scry1 - 2 * HOLLOW_BORDER);
+  set_colour (WINBG_LIGHT);
+  XDrawLine (dpy, drw, gc, scrx1, scry2, scrx2, scry2);
+  XDrawLine (dpy, drw, gc, scrx2, scry1, scrx2, scry2);
+  set_colour (WINBG_DARK);
+  XDrawLine (dpy, drw, gc, scrx1, scry1, scrx2, scry1);
+  XDrawLine (dpy, drw, gc, scrx1, scry1, scrx1, scry2);
+  drw_mods++;
+  pop_colour ();
+#endif
+}
+
+
+/*
+ *	DrawScreenMeter - draw a meter bar on the screen
+ *
+ *	In a hollow box; max. value = 1.0
+ */
+void DrawScreenMeter (int scrx1, int scry1, int scrx2, int scry2, float value)
+{
+#if defined Y_BGI
+  if (value < 0.0)
+    value = 0.0;
+  if (value > 1.0)
+    value = 1.0;
+  setfillstyle (1, TranslateToDoomColor (BLACK));
+  bar (scrx1 + 1 + (int) ((scrx2 - scrx1 - 2) * value), scry1 + 1, scrx2 - 1, scry2 - 1);
+  setfillstyle (1, TranslateToDoomColor (LIGHTGREEN));
+  bar (scrx1 + 1, scry1 + 1, scrx1 + 1 + (int) ((scrx2 - scrx1 - 2) * value), scry2 - 1);
+#elif defined Y_X11
+  printf ("DrawScreenMeter()\n");  // FIXME
+#endif
+}
+
+
+// Shared by DrawScreenText() and DrawScreenString()
+
+/* Coordinates of first character of last string drawn with
+   DrawScreenText() or DrawScreenString(). */
+static int lastx0;
+static int lasty0;
+
+// Where the last DrawScreen{Text,String}() left the "cursor".
+static int lastxcur;
+static int lastycur;
+
+
+/*
+ *	DrawScreenText - format and display a string
+ *
+ *	Write text to the screen in printf() fashion.
+ *	The top left corner of the first character is at (<scrx>, <scry>)
+ *	If <scrx> == -1, the text is printed at the same abscissa
+ *	as the last text printed with this function.
+ *	If <scry> == -1, the text is printed one line (FONTH pixels)
+ *	below the last text printed with this function.
+ *	If <msg> == NULL, no text is printed. Useful to set the
+ *	coordinates for the next time.
+ */
+void DrawScreenText (int scrx, int scry, const char *msg, ...)
+{
+  char temp[120];
+  va_list args;
+
+  // <msg> == NULL: print nothing, just set the coordinates.
+  if (msg == NULL)
+  {
+    if (scrx != -1 && scrx != -2)
+    {
+      lastx0   = scrx;
+      lastxcur = scrx;
+    }
+    if (scry != -1 && scry != -2)
+    {
+      lasty0   = scry;  // Note: no "+ FONTH"
+      lastycur = scry;
+    }
+    return;
+  }
+
+  va_start (args, msg);
+  y_vsnprintf (temp, sizeof temp, msg, args);
+  DrawScreenString (scrx, scry, temp);
+}
+
+
+/*
+ *	DrawScreenString - display a string
+ *
+ *	Same thing as DrawScreenText() except that the string is
+ *	printed verbatim (no formatting or conversion).
+ *
+ *	A "\1" in the string is not displayed but causes
+ *	subsequent characters to be displayed in WINLABEL (or
+ *	WINLABEL_DIM if the current colour before the function
+ *	was called was WINFG_DIM).
+ *
+ *	A "\2" in the string is not displayed but causes
+ *	subsequent characters to be displayed in the same colour
+ *	that was active before the function was called.
+ *
+ *	The string can contain any number of "\1" and "\2".
+ *	Regardless, upon return from the function, the current
+ *	colour is restored to what it was before the function
+ *	was called.
+ *
+ *	This colour switching business was hacked in a hurry.
+ *	Feel free to improve it.
+ */
+void DrawScreenString (int scrx, int scry, const char *str)
+{
+  int x; int y;
+
+  /* FIXME originally, the test was "< 0". Because it broke
+     when the screen was too small, I changed it to a more
+     specific "== -1". A quick and very dirty hack ! */
+  if (scrx == -1)
+    x = lastx0;
+  else if (scrx == -2)
+    x = lastxcur;
+  else
+    x = scrx;
+  if (scry == -1)
+    y = lasty0;
+  else if (scry == -2)
+    y = lastycur;
+  else
+    y = scry;
+  size_t len = strlen (str);
+#if defined Y_BGI
+  outtextxy (x, y, str);
+  // FIXME implement colour changes (\1, \2)
+#elif defined Y_X11
+  if (strchr (str, '\1') == 0)
+  {
+    XDrawString (dpy, drw, gc, x - font_xofs, y + font_yofs, str, len);
+  }
+  else
+  {
+    acolour_t save = get_colour ();
+    int xx = x;
+    len = 0;
+    for (const char *p = str; *p != '\0';)
+    {
+      int i;
+      for (i = 0; p[i] != '\0' && p[i] != '\1' && p[i] != '\2'; i++)
+	;
+      len += i;
+      if (i > 0)
+      {
+	XDrawString (dpy, drw, gc, xx - font_xofs, y + font_yofs, p, i);
+	xx += i * FONTW;
+      }
+      if (p[i] == '\0')
+	break;
+      if (p[i] == '\1')
+	set_colour (save == WINFG_DIM ? WINLABEL_DIM : WINLABEL);
+      else if (p[i] == '\2')
+	set_colour (save);
+      i++;
+      p += i;
+    }
+    set_colour (save);
+  }
+  if (text_dot)
+    XDrawPoint (dpy, drw, gc, x, y);
+  drw_mods++;
+#endif
+
+  lastxcur = x + FONTW * len;
+  lastycur = y;
+  if (scrx != -2)
+    lastx0 = x;
+  if (scry != -2)
+    lasty0 = y + FONTH;
+}
+
+
+/*
+ *	DrawScreenChar - display a character
+ *
+ *	Same thing as DrawScreenText() except that the string is
+ *	printed verbatim (no formatting or conversion).
+ */
+void DrawScreenChar (int x, int y, char c)
+{
+#if defined Y_BGI
+  char buf[2];
+  buf[0] = c;
+  buf[1] = '\0';
+  outtextxy (x, y, buf);
+#elif defined Y_X11
+  XDrawString (dpy, drw, gc, x - font_xofs, y + font_yofs, &c, 1);
+  if (text_dot)
+    XDrawPoint (dpy, drw, gc, x, y);
+  drw_mods++;
+#endif
+}
+
+
+/*
+ *	DrawPointer  - draw (or erase) the pointer if we aren't using the mouse
+ */
+void DrawPointer (bool rulers)
+{
+#ifdef Y_BGI
+  int r;
+
+  // Use XOR mode : drawing the pointer twice erases it
+  SetDrawingMode (1);
+  // Draw the pointer
+  if (rulers)
+  {
+    set_colour (MAGENTA);
+    r = (int) (512 * Scale);
+    circle (is.x, is.y, r);
+    r >>= 1;
+    circle (is.x, is.y, r);
+    r >>= 1;
+    circle (is.x, is.y, r);
+    r >>= 1;
+    circle (is.x, is.y, r);
+    r = (int) (1024 * Scale);
+    line (is.x - r, is.y, is.x + r, is.y);
+    line (is.x, is.y - r, is.x, is.y + r);
+  }
+  else
+  {
+    set_colour (YELLOW);
+    line (is.x - 15, is.y - 13, is.x + 15, is.y + 13);
+    line (is.x - 15, is.y + 13, is.x + 15, is.y - 13);
+  }
+  // Restore normal write mode
+  SetDrawingMode (0);
+#else
+  ;
+#endif
+}
+
+
+#ifdef Y_BGI
+/*
+ *	TranslateToDoomColor - translate a standard color to Doom palette 0 (approx.)
+ */
+int TranslateToDoomColor (int colour)
+{
+  if (GfxMode < 0)
+    switch (colour)
+    {
+      case BLACK:
+	return 0;
+      case BLUE:
+	return 202;
+      case GREEN:
+	return 118;
+      case CYAN:
+	return 194;
+      case RED:
+	return 183;
+      case MAGENTA:
+	return 253;
+      case BROWN:
+	return 144;
+      case LIGHTGREY:
+	return 88;
+      case DARKGREY:
+	return 96;
+      case LIGHTBLUE:
+	return 197;
+      case LIGHTGREEN:
+	return 112;
+      case LIGHTCYAN:
+	return 193;
+      case LIGHTRED:
+	return 176;
+      case LIGHTMAGENTA:
+	return 250;
+      case YELLOW:
+	return 231;
+      case WHITE:
+	return 4;
+    }
+  return colour;
+}
+#endif
+
+
+#if defined Y_BGI && defined CIRRUS_PATCH
+/*
+ *	Cirrus Logic Hardware Mouse Cursor Stuff
+ */
+
+#define CRTC 0x3D4
+#define ATTR 0x3C0
+#define SEQ  0x3C4
+#define GRC  0x3CE
+#define LOBYTE(w)  ((unsigned char)(w))
+#define HIBYTE(w)  ((unsigned char)((unsigned int)(w) >> 8))
+
+
+unsigned rdinx (unsigned pt, unsigned inx)
+{
+  if (pt == ATTR)
+    inportb (CRTC + 6);
+  outportb (pt, inx);
+  return inportb (pt + 1);
+}
+
+
+void wrinx (int pt, unsigned inx, unsigned val)
+{
+  if (pt == ATTR)
+  {
+    inportb (CRTC + 6);
+    outportb (pt, inx);
+    outportb (pt, val);
+  }
+  else
+  {
+    outportb (pt, inx);
+    outportb (pt + 1, val);
+  }
+}
+
+
+void modinx (unsigned pt, unsigned inx, unsigned mask, unsigned nwv)
+{
+  unsigned temp;
+
+  temp = (rdinx (pt, inx) & ~mask) + (nwv & mask);
+  wrinx (pt, inx, temp);
+}
+
+
+void clrinx (unsigned pt, unsigned inx, unsigned val)
+{
+  unsigned x;
+
+  x = rdinx (pt, inx);
+  wrinx (pt, inx, x & ~val);
+}
+
+
+void SetHWCursorPos (unsigned x, unsigned y)
+{
+  outport (SEQ, (x << 5) | 0x10);
+  outport (SEQ, (y << 5) | 0x11);
+}
+
+
+void SetHWCursorCol (long fgcol, long bgcol)
+{
+  modinx (SEQ, 0x12, 3, 2);
+  outportb (0x3C8, 0xFF);
+  outportb (0x3C9, LOBYTE (fgcol) >> 2);
+  outportb (0x3C9, HIBYTE (bgcol) >> 2);
+  outportb (0x3C8, 0);
+  outportb (0x3C9, LOBYTE (bgcol) >> 2);
+  outportb (0x3C9, HIBYTE (bgcol) >> 2);
+  outportb (0x3C9, bgcol >> 18);
+  modinx (SEQ, 0x12, 3, 1);
+}
+
+
+void CopyHWCursorMap (unsigned bytes)
+{
+  char    *curmapptr = 0xA000FF00L;
+  unsigned lbank = (1024 / 64) - 1;
+
+  if ((rdinx (GRC, 0x0B) & 32)==0)
+    lbank = lbank << 2;
+  wrinx (GRC, 9, lbank << 2);
+  memmove (curmapptr, &mp, bytes);
+}
+
+
+void SetHWCursorMap (char *map)
+{
+  memmove (&mp, map, 128);
+  memmove (&mp + 128, &mp, 128);
+  CopyHWCursorMap (256);
+  SetHWCursorCol (0xFF00000L, 0xFF);
+  wrinx (SEQ, 0x13, 0x3F);
+}
+
+#endif  /* Y_BGI && CIRRUS_PATCH */
+
+
+#ifdef Y_DOS
+static int cooked_installuserdriver (const char far *__name,
+                                    int huge (*detect)(void))
+{
+  char savecwd[PATH_MAX+1];
+  int gdriver;
+
+  getcwd (savecwd, PATH_MAX);
+  if (al_fchdir (install_dir))
+    fatal_error ("installuserdriver: chdir1 error (%s)", strerror (errno));
+  gdriver = installuserdriver (__name, detect);
+  if (al_fchdir (savecwd))
+    fatal_error ("installuserdriver: chdir2 error (%s)", strerror (errno));
+  return gdriver;
+}
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/gfx.h	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,129 @@
+/*
+ *	gfx.h
+ *	AYM 1998-08-01
+ */
+
+
+#ifndef YH_GFX  /* Prevent multiple inclusion */
+#define YH_GFX  /* Prevent multiple inclusion */
+
+
+/* Width and height of font cell. Those figures are not meant to
+   represent the actual size of the character but rather the step
+   between two characters. For example, for the original 8x8 BGI
+   font, FONTW was 8 and FONTH was 10. DrawScreenText() is supposed
+   to draw characters properly _centered_ within that space, taking
+   into account the optional underscoring. */
+extern unsigned FONTW;
+extern unsigned FONTH;
+extern int font_xofs;
+extern int font_yofs;
+
+
+/* This number is the Y offset to use when underscoring a character.
+   For example, if you want to draw an underscored "A" at (x,y),
+   you should do :
+     DrawScreenString (x, y,         "A");
+     DrawScreenString (x, y + FONTU, "_"); */
+#define FONTU  1
+
+/* Narrow spacing around text. That's the distance in pixels
+   between the characters and the inner edge of the box. */
+#define NARROW_HSPACING  4
+#define NARROW_VSPACING  2
+
+/* Wide spacing around text. That's the distance in pixels
+   between the characters and the inner edge of the box. */
+#define WIDE_HSPACING  FONTW
+#define WIDE_VSPACING  (FONTH / 2)
+
+/* Boxes */
+#define BOX_BORDER    2	 // Offset between outer and inner edges of a 3D box
+#define NARROW_BORDER 1	 // Same thing for a shallow 3D box
+#define HOLLOW_BORDER 1	 // Same thing for a hollow box
+#define BOX_VSPACING  WIDE_VSPACING  // Vertical space between two hollow boxes
+
+/* Parameters set by command line args and configuration file */
+extern const char *BGIDriver;	// BGI: default extended BGI driver
+extern bool  CirrusCursor;	// use HW cursor on Cirrus Logic VGA cards
+extern bool  FakeCursor;	// use a "fake" mouse cursor
+extern const char *font_name;	// X: the name of the font to load
+				// (if NULL, use the default)
+extern Win_dim initial_window_width;// X: the name says it all
+extern Win_dim initial_window_height;// X: the name says it all
+extern int   no_pixmap;		// X: use no pixmap -- direct window output
+extern int   VideoMode;		// BGI: default video mode for VESA cards
+
+/* Global variables */
+extern int   GfxMode;		// current graphics mode, or 0 for text
+extern int   OrigX;		// Map X-coord of centre of screen/window
+extern int   OrigY;		// Map Y-coord of centre of screen/window
+extern int   ScrCenterX;	// Display X-coord of center of screen/window
+extern int   ScrCenterY;	// Display Y-coord of center of screen/window
+#ifdef Y_X11
+typedef unsigned long xpv_t;	// The type of a pixel value in X's opinion
+#ifdef X_PROTOCOL
+extern Display *dpy;
+extern int      scn;
+extern Colormap cmap;		// The X colormap
+extern Window   win;
+extern Drawable drw;
+extern GC       gc;
+extern Visual  *win_vis;	// The visual for win
+extern int      win_depth;	// The depth of win in bits
+extern int      win_bpp;	// The depth of win in bytes
+extern int	x_server_big_endian;	// Is the X server big-endian ?
+extern int      ximage_bpp;	// Number of bytes per pixels in XImages
+extern int      ximage_quantum;	// Pad XImage lines to a mult of that many B.
+#endif  // ifdef X_PROTOCOL
+#endif  // ifdef Y_X11
+extern int	text_dot;     // DrawScreenText()/DrawScreenString() debug flag
+
+/* gfx.cc */
+int InitGfx (void);
+void SwitchToVGA256 (void);
+void SwitchToVGA16 (void);
+void TermGfx (void);
+void SetWindowSize (int width, int height);
+void ClearScreen (void);
+void update_display ();
+void force_window_not_pixmap ();
+void SetLineThickness (int thick);
+void SetDrawingMode (int _xor);
+void DrawMapCircle (int, int, int);
+void DrawMapLine (int mapx1, int mapy1, int mapx2, int mapy2);
+void DrawMapVector (int, int, int, int);
+void DrawMapArrow (int, int, unsigned);
+void DrawScreenLine (int, int, int, int);
+void DrawScreenRect (int x, int y, int width, int height);
+void DrawScreenBox (int, int, int, int);
+void DrawScreenBoxwh (int scrx0, int scry0, int width, int height);
+void DrawScreenBox3D (int, int, int, int);
+void DrawScreenBox3DShallow (int, int, int, int);
+void DrawScreenBoxHollow (int x0, int y0, int x1, int y1, acolour_t colour);
+void draw_box_border (int x, int y, int width, int height,
+   int thickness, int raised);
+void DrawScreenText (int, int, const char *, ...);
+void DrawScreenString (int, int, const char *);
+void DrawScreenChar (int x, int y, char c);
+void DrawPointer (bool);
+void DrawScreenMeter (int, int, int, int, float);
+void DrawScreenLineLen (int x, int y, int width, int height);
+int TranslateToDoomColor (int);
+#if defined Y_BGI && defined CIRRUS_PATCH
+void SetHWCursorPos (unsigned, unsigned);
+void SetHWCursorCol (long, long);
+void SetHWCursorMap (char *);
+#endif /* Y_BGI && CIRRUS_PATCH */
+#ifdef PCOLOUR_NONE
+void set_pcolour (pcolour_t colour);
+#endif
+acolour_t get_colour ();
+void set_colour (acolour_t);
+void push_colour (acolour_t colour);
+void pop_colour (void);
+void draw_point (int x, int y);
+void draw_map_point (int mapx, int mapy);
+
+
+#endif  /* DO NOT ADD ANYTHING AFTER THIS LINE */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/gfx2.cc	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,110 @@
+/*
+ *	gfx2.cc
+ *	Graphics routines for debugging.
+ *	AYM 1998-11-17
+ */
+
+
+/*
+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 <X11/Xlib.h>
+#include "colour.h"
+#include "gcolour2.h"
+#include "gfx.h"
+#include "rgb.h"
+
+
+/*
+ *	show_font
+ *	Draw all of the characters of the font in a window
+ */
+void show_font ()
+{
+int width  = 2 * BOX_BORDER + 2 * WIDE_HSPACING + 16 * FONTW;
+int height = 2 * BOX_BORDER + 2 * WIDE_VSPACING + 16 * FONTH;
+int x0 = (ScrMaxX + 1 - width) / 2;
+int y0 = (ScrMaxY + 1 - height) / 2;
+int text_x0 = x0 + BOX_BORDER + WIDE_HSPACING;
+int text_y0 = y0 + BOX_BORDER + WIDE_VSPACING;
+
+DrawScreenBox3D (x0, y0, x0 + width - 1, y0 + height - 1);
+set_colour (WINFG);
+char buf[17];
+for (int i = 0; i < 16; i ++)
+   {
+   for (int j = 0; j < 16; j++)
+      buf[j] = 16 * i + j;
+   XDrawString (dpy, drw, gc,
+      text_x0 - font_xofs,
+      text_y0 + FONTH * i + font_yofs,
+      buf, 16);
+   }
+get_key_or_click ();
+}
+
+
+/*
+ *	show_colours
+ */
+void show_colours ()
+{
+int ncolours = get_pcolours_count ();
+const int columns = 16;
+int lines = (ncolours + columns - 1) / columns;
+const int pixels = 16;
+int width = 2 * BOX_BORDER + 2 * WIDE_HSPACING + columns * (pixels + 1);
+int height = 2 * BOX_BORDER + 2 * WIDE_VSPACING + lines * (pixels + 1);
+int x0 = (ScrMaxX - width) / 2;
+int y0 = (ScrMaxY - height) / 2;
+
+DrawScreenBox3D (x0, y0, x0 + width - 1, y0 + height - 1);
+
+// Draw a small square for each colour
+
+int ix0 = x0 + BOX_BORDER + WIDE_HSPACING;
+int x = 0;  // Initialized to prevent GCC from warning
+int y = 0;  // Initialized to prevent GCC from warning
+push_colour (0);  // Save current colour
+for (int n = 0; n < ncolours; n++)
+   {
+   if (n % columns == 0)
+      {
+      x = ix0;
+      if (n == 0)
+         y = y0 + BOX_BORDER + WIDE_VSPACING;
+      else
+         y += pixels + 1;
+      }
+   else
+      x += pixels + 1;
+   set_pcolour (get_pcolour_pcn (n));
+   DrawScreenBox (x, y, x + pixels - 1, y + pixels - 1);
+   }
+pop_colour ();  // Restore current colour
+
+get_key_or_click ();
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/gfx2.h	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,9 @@
+/*
+ *	gfx2.h
+ *	AYM 1998-11-17
+ */
+
+
+void show_font ();
+void show_colours ();
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/gfx3.cc	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,102 @@
+/*
+ *	gfx3.cc
+ *	Graphics routines
+ *	AYM 1999-06-06
+ */
+
+
+/*
+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 <X11/Xlib.h>
+#include "colour.h"
+#include "gfx.h"
+#include "gfx3.h"
+#include "rgbbmp.h"
+
+
+/*
+ *	window_to_rgbbmp
+ *	Grab a rectangle from the window or screen into an
+ *	Rgbbmp, in a portable fashion.
+ */
+void window_to_rgbbmp (int x, int y, int width, int height, Rgbbmp &b)
+{
+#if defined Y_X11
+  b.resize (width, height);
+  // FIXME
+  for (int y = 0; y < b.height (); y++)
+    for (int x = 0; x < b.width (); x++)
+      b.set_r (x, y, 255 * (b.height () - y) / b.height ());
+  for (int y = 0; y < b.height (); y++)
+    for (int x = 0; x < b.width (); x++)
+      b.set_g (x, y, 255 * (b.width () - x) / b.width ());
+  for (int y = 0; y < b.height (); y++)
+    for (int x = 0; x < b.width (); x++)
+      b.set_b (x, y, 255 * (x + y) / (b.width () + b.height ()));
+#elif defined Y_BGI
+  printf ("window_to_rgb: unimplemented\n");
+  return 0;
+#endif
+}
+
+
+/*
+ *	rgbbmp_to_rawppm
+ *	Return 0 on success, non-zero on failure.
+ */
+int rgbbmp_to_rawppm (const Rgbbmp &b, const char *file_name)
+{
+  FILE *fd;
+  fd = fopen (file_name, "wb");
+  if (fd == 0)
+  {
+    fflush (stdout);
+    fprintf (stderr, "Can't open \"%s\" for writing (%s)\n",
+	file_name, strerror (errno));
+    fflush (stderr);
+    return 1;
+  }
+  fprintf (fd,	"P6\n"
+		"# Created by Yadex %s\n"
+		"%d %d\n"
+		"255\n", yadex_version, b.width (), b.height ());
+  for (int y = 0; y < b.height (); y++)
+    for (int x = 0; x < b.width (); x++)
+    {
+      putc (b.get_r (x, y), fd);
+      putc (b.get_g (x, y), fd);
+      putc (b.get_b (x, y), fd);
+    }
+  if (fclose (fd))
+  {
+    fflush (stdout);
+    fprintf (stderr, "Write error in \"%s\"\n", file_name);
+    fflush (stderr);
+    return 1;
+  }
+  return 0;
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/gfx3.h	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,13 @@
+/*
+ *	gfx3.h
+ *	AYM 1999-06-06
+ */
+
+
+#include "rgbbmp.h"
+
+
+void window_to_rgbbmp (int x, int y, int width, int height, Rgbbmp &b);
+int rgbbmp_to_rawppm (const Rgbbmp &b, const char *file_name);
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/gotoobj.cc	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,154 @@
+/*
+ *	gotoobj.cc
+ *	AYM 1998-09-06
+ */
+
+
+/*
+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 "gfx.h"
+#include "gotoobj.h"
+#include "levels.h"
+#include "objects.h"
+#include "objid.h"
+#include "x_hover.h"
+
+
+/*
+ *	CenterMapAroundCoords
+ *	Change the view so that the map coordinates (xpos, ypos)
+ *	appear at the centre of the window
+ */
+void CenterMapAroundCoords (int xpos, int ypos)
+{
+OrigX = xpos;
+OrigY = ypos;
+/* AYM 1998-09-20 This is a DOS-ism. IIRC, the ICCCM says an
+   application program should generally not mess with the
+   pointer. */
+#if 0
+is.x = ScrCenterX;
+is.y = ScrCenterY;
+#endif
+}
+
+
+/*
+ *	focus_on_map_coords
+ *	Change the view so that the map coordinates (xpos, ypos)
+ *	appear under the pointer
+ */
+void focus_on_map_coords (int x, int y)
+{
+OrigX = x - (MAPX (is.x) - OrigX);
+OrigY = y - (MAPY (is.y) - OrigY);
+}
+
+
+/*
+ *	sector_under_pointer
+ *	Convenience function
+ */
+inline int sector_under_pointer ()
+{
+Objid o;
+GetCurObject (o, OBJ_SECTORS, MAPX (is.x), MAPY (is.y));
+return o.num;
+}
+
+
+/*
+  centre the map around the object and zoom in if necessary
+*/
+
+void GoToObject (const Objid& objid) /* SWAP! */
+{
+int   xpos, ypos;
+int   xpos2, ypos2;
+int   sd1, sd2;
+float oldscale;
+
+GetObjectCoords (objid.type, objid.num, &xpos, &ypos);
+focus_on_map_coords (xpos, ypos);
+oldscale = Scale;
+
+/* I ifdef'd out this block because the only thing it really
+   does is (uselessly) messing the zoom factor up when there are
+   superimposed objects and we're trying to focus on the
+   highest-numbered (and therefore hidden) one. AYM 1999-07-26 */
+#if 0
+/* zoom in until the object can be selected */
+while (Scale < 8.0
+   && GetCurObject (objid.type, MAPX (is.x), MAPY (is.y)) != objid.num)
+   {
+   if (Scale < 1.0)
+      Scale = 1.0 / ((1.0 / Scale) - 1.0);
+   else
+      Scale = Scale * 2.0;
+   }
+#endif
+
+/* Special case for sectors: if a sector contains other sectors,
+   or if its shape is such that it does not contain its own
+   geometric centre, zooming in on the centre won't help. So I
+   choose a linedef that borders the sector and focus on a point
+   between the centre of the linedef and the centre of the
+   sector. If that doesn't help, I try another linedef.
+
+   This algorithm is not perfect but it works rather well with
+   most well-constituted sectors. It does not work so well for
+   unclosed sectors, though (but it's partly GetCurObject()'s
+   fault). */
+if (objid.type == OBJ_SECTORS && sector_under_pointer () != objid.num)
+   {
+   /* restore the Scale */
+   Scale = oldscale;
+   for (int n = 0; n < NumLineDefs; n++)
+      {
+      ObjectsNeeded (OBJ_LINEDEFS, 0);
+      sd1 = LineDefs[n].sidedef1;
+      sd2 = LineDefs[n].sidedef2;
+      ObjectsNeeded (OBJ_SIDEDEFS, 0);
+      if (sd1 >= 0 && SideDefs[sd1].sector == objid.num
+	|| sd2 >= 0 && SideDefs[sd2].sector == objid.num)
+	 {
+	 GetObjectCoords (OBJ_LINEDEFS, n, &xpos2, &ypos2);
+	 int d = ComputeDist (abs (xpos - xpos2), abs (ypos - ypos2)) / 7;
+	 if (d <= 1)
+	   d = 2;
+	 xpos = xpos2 + (xpos - xpos2) / d;
+	 ypos = ypos2 + (ypos - ypos2) / d;
+	 focus_on_map_coords (xpos, ypos);
+	 if (sector_under_pointer () == objid.num)
+	    break;
+	 }
+      }
+   }
+if (UseMouse)
+   SetMouseCoords (is.x, is.y);
+}
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/gotoobj.h	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,12 @@
+/*
+ *	gotoobj.h
+ *	AYM 1998-09-06
+ */
+
+
+class Objid;
+
+
+void CenterMapAroundCoords (int, int);
+void GoToObject (const Objid& objid); /* SWAP! */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/help1.cc	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,116 @@
+/*
+ *	help1.cc
+ *	AYM 1998-10-03
+ */
+
+
+/*
+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 "cfgfile.h"
+#include "help1.h"
+
+
+/*
+ *	what
+ *	Return a static string containing
+ *	the name and version number of Yadex.
+ */
+const char *what ()
+{
+static char buf[40];
+y_snprintf (buf, sizeof buf, "Yadex %s (%s)", yadex_version, yadex_source_date);
+return buf;
+}
+
+
+/*
+ *	print_usage
+ *	Print the program usage.
+ */
+void print_usage (FILE *fd)
+{
+fprintf (fd, "%s\n", what ());
+fprintf (fd, "Usage: yadex [options] [<pwad_file> ...]\n");
+fprintf (fd, "Options:\n");
+dump_command_line_options (fd);
+fprintf (fd, " %-33sSame as -?\n", "--help");
+fprintf (fd, " %-33sPrint version and exit\n", "--version");
+fprintf (fd, "Put a \"+\" instead of a \"-\" before boolean options"
+             " to reverse their effect.\n");
+}
+
+
+/*
+ *	print_welcome
+ *	Print the welcome message
+ */
+void print_welcome (FILE *fd)
+{
+#ifdef OLD_MESSAGE
+fprintf (fd, "\n");
+fprintf (fd, "*----------------------------------------------------------------------------*\n");
+fprintf (fd, "| Welcome to DEU!  This is a poweful utility and, like all good tools, it    |\n");
+fprintf (fd, "| comes with its user's manual.  Please print and read DEU.TXT if you want   |\n");
+fprintf (fd, "| to discover all the features of this program.  If you are new to DEU, the  |\n");
+fprintf (fd, "| tutorial will show you how to build your first level.                      |\n");
+fprintf (fd, "|                                                                            |\n");
+fprintf (fd, "| If you are an experienced DEU user and want to know what has changed since |\n");
+fprintf (fd, "| the last version, you should read the revision history in README.1ST.      |\n");
+fprintf (fd, "|                                                                            |\n");
+fprintf (fd, "| And if you have lots of suggestions for improvements, bug reports, or even |\n");
+fprintf (fd, "| complaints about this program, be sure to read README.1ST first.           |\n");
+fprintf (fd, "| Hint: you can easily disable this message.  Read the docs carefully...     |\n");
+fprintf (fd, "*----------------------------------------------------------------------------*\n");
+#else
+
+fprintf (fd, "\n"
+                "** Welcome to Yadex. Glad you've made it so far. :-)\n");
+#if defined Y_ALPHA
+fprintf (fd, "**\n"
+		"** This is an alpha version. Expect it to have bugs. Do\n"
+		"** yourself a favour and make backup copies of your data !\n"
+		"**\n");
+#elif defined Y_BETA
+fprintf (fd, "**\n"
+		"** This is a beta version. It is believed to be reasonably\n"
+		"** stable but it's been given only limited testing. So do\n"
+		"** yourself a favour and make backup copies of your data.\n"
+		"**\n");
+#else
+fprintf (fd, "**\n"
+		"** This version is believed to be stable but you never\n"
+		"** know so make backup copies of your data anyway.\n"
+		"**\n");
+#endif
+fprintf (fd, "** Yadex is work in progress. Subscribe to yadex-announce\n");
+fprintf (fd, "** or keep an eye on the web page.\n");
+fprintf (fd, "** To edit an existing level, type \"e <level_name>\".\n");
+fprintf (fd, "** To create a new level, type \"c\".\n"
+                "\n");
+#endif
+}
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/help1.h	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,11 @@
+/*
+ *	help1.h
+ *	AYM 1998-10-03
+ */
+
+
+const char *what ();
+void print_usage (FILE *fd);
+void print_welcome (FILE *fd);
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/help2.cc	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,178 @@
+/*
+ *	help2.cc
+ *	AYM 1998-08-17
+ */
+
+
+/*
+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 "credits.h"
+#include "gfx.h"
+#include "help1.h"  // what()
+#include "help2.h"
+
+
+/*
+   display the help screen
+ */
+
+static const char *help_text[] =
+{
+  "             Keyboard :",
+  "Esc/q Quit                      Pgup  Scroll up",
+  "                                Pgdn  Scroll down",
+  "Tab   Next mode                 Home  Scroll left",
+  "ShiftTab Previous mode          End   Scroll right",
+  "l     Linedefs & sidedefs mode  '     Go to centre of map",
+  "s     Sectors mode              `     Show whole map",
+  "t     Things mode               n,>   Jump to next object",
+  "v     Vertices mode             p,<   Jump to previous object",
+  "&     Show/hide object numbers  j,#   Jump to object #N",
+  "%%     Show/hide sprites",
+  "                                +/-   Zoom in/out",
+  "Ins   Insert a new object       g/G   Decr./incr. the grid step",
+  "Del   Delete the object(s)      h     Hide/show the grid",
+  "Retn  Edit object properties    H     Reset grid step to the max",
+  "x/w   Spin things cw/ccw        z     Lock the grid step",
+  "x     Split linedefs            y     Snap to grid on/off",
+  "w     Split linedefs & sector   Space Toggle extra zoom",
+  "a     Set things/ld flags",
+  "b     Toggle things/ld flags    e     Select linedefs in path",
+  "c     Clear things/ld flags     E     Select 1s linedefs in path",
+  "F8    Misc. operations",
+  "F9    Insert compound object    F5    Preferences",
+  "                                F10   Checks",
+  "             Mouse :",
+  "- Clicking on an object with the left button selects it (and",
+  "  unselects everything else unless [Ctrl] is pressed).",
+  "- Clicking on an already selected object with the left button with",
+  "  [Ctrl] pressed unselects it.",
+  "- Double clicking on an object allows to change its properties.",
+  "- You can also drag objects with the left button.",
+  "- Clicking on an empty space with the left button and moving draws",
+  "  a rectangular selection box. Releasing the button selects",
+  "  everything in that box (and unselects everything else unless",
+  "  [Ctrl] is pressed).",
+  "- Wheel or buttons 4 and 5: zoom in and out",
+  NULL
+};
+
+void DisplayHelp () /* SWAP! */
+{
+  int x0;
+  int y0;
+  int width;
+  int height;
+  size_t maxlen = 0;
+  int lines = 4;
+
+  for (const char **str = help_text; *str; str++)
+  {
+    size_t len = strlen (*str);
+    maxlen = y_max (maxlen, len);
+    lines++;
+  }
+  width  = (maxlen + 4) * FONTW + 2 * BOX_BORDER;
+  height = lines * FONTH + 2 * BOX_BORDER;
+  x0 = (ScrMaxX + 1 - width) / 2;
+  y0 = (ScrMaxY + 1 - height) / 2;
+  HideMousePointer ();
+  /* put in the instructions */
+  DrawScreenBox3D (x0, y0, x0 + width - 1, y0 + height - 1);
+  set_colour (LIGHTCYAN);
+  DrawScreenText (x0 + BOX_BORDER + (width - 5 * FONTW) / 2,
+		  y0 + BOX_BORDER + FONTH / 2,
+		  "Yadex");
+  set_colour (WINFG);
+  DrawScreenText (x0 + BOX_BORDER + 2 * FONTW, y0 + BOX_BORDER + FONTH, "");
+  for (const char **str = help_text; *str; str++)
+     DrawScreenText (-1, -1, *str);
+  set_colour (WINTITLE);
+  DrawScreenText (-1, -1, "Press any key to return to the editor...");
+  get_key_or_click ();
+  ShowMousePointer ();
+}
+
+
+/*
+ *	about_yadex()
+ *	The name says it all.
+ */
+void about_yadex ()
+{
+  int widthc  = 57;
+  int heightc = 19;
+
+  for (const char *const *s = yadex_copyright; *s != 0; s++)
+  {
+    if (strlen (*s) > size_t (widthc))
+      widthc = strlen (*s);
+    heightc++;
+  }
+  int width   = 2 * BOX_BORDER + 2 * WIDE_HSPACING + widthc * FONTW;
+  int height  = 2 * BOX_BORDER + 2 * WIDE_VSPACING + heightc * FONTH;
+  int x0 = (ScrMaxX + 1 - width) / 2;
+  int y0 = (ScrMaxY + 1 - height) / 2;
+
+  HideMousePointer ();
+  DrawScreenBox3D (x0, y0, x0 + width - 1, y0 + height - 1);
+  push_colour (WINFG);
+  push_colour (WINFG_HL);
+  DrawScreenText (x0 + BOX_BORDER + WIDE_HSPACING,
+		  y0 + BOX_BORDER + WIDE_VSPACING, what ());
+  pop_colour ();
+  DrawScreenText (-1, -1, "");
+  for (const char *const *s = yadex_copyright; *s != 0; s++)
+    DrawScreenText (-1, -1, *s);
+  DrawScreenText (-1, -1, "");
+  push_colour (WINFG_HL);
+  DrawScreenText (-1, -1, "Home page :");
+  pop_colour ();
+  DrawScreenText (-1, -1, "http://www.teaser.fr/~amajorel/yadex/");
+  DrawScreenText (-1, -1, "http://www.linuxgames.com/yadex/");
+  DrawScreenText (-1, -1, "");
+  push_colour (WINFG_HL);
+  DrawScreenText (-1, -1, "Mailing lists :");
+  pop_colour ();
+  DrawScreenText (-1, -1, "you-know-what@freelists.org");
+  DrawScreenText (-1, -1, "you-know-what-announce@freelists.org");
+  DrawScreenText (-1, -1, "To subscribe, send mail with the subject");
+  DrawScreenText (-1, -1, "\"subscribe <list_name>\" to ecartis@freelists.org.");
+  DrawScreenText (-1, -1, "");
+  push_colour (WINFG_HL);
+  DrawScreenText (-1, -1, "Maintainer :");
+  pop_colour ();
+  DrawScreenText (-1, -1, "André Majorel (http://www.teaser.fr/~amajorel/)");
+  DrawScreenText (-1, -1, "Send all email to you-know-what@freelists.org, NOT to me.");
+  DrawScreenText (-1, -1, "");
+  DrawScreenText (-1, -1, "");
+  set_colour (WINTITLE);
+  DrawScreenText (-1, -1, "Press any key to return to the editor...");
+  pop_colour ();
+  get_key_or_click ();
+  ShowMousePointer ();
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/help2.h	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,9 @@
+/*
+ *	help2.h
+ *	AYM
+ */
+
+
+void DisplayHelp ();
+void about_yadex ();
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/highlt.cc	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,62 @@
+/*
+ *	highlt.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 "highlt.h"
+#include "objects.h"
+#include "objid.h"
+
+
+highlight_c::highlight_c (void)
+{
+obj.nil ();
+obj_disp.nil ();
+}
+
+
+void highlight_c::draw (void)
+{
+if (! obj_disp () && obj ())
+   {
+   HighlightObject (obj.type, obj.num, YELLOW);
+   obj_disp = obj;
+   }
+}
+
+
+void highlight_c::undraw (void)
+{
+if (obj_disp () && ! (obj_disp == obj))
+   {
+   HighlightObject (obj_disp.type, obj_disp.num, YELLOW);
+   obj_disp.nil ();
+   }
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/highlt.h	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,52 @@
+/*
+ *	highlt.h
+ *	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 "edwidget.h"
+#include "objid.h"
+
+
+class highlight_c : public edwidget_c
+   {
+   public :
+      highlight_c (void);
+      void set (Objid& obj) { this->obj = obj; }
+
+      /* Methods declared in edwidget */
+      void unset () { obj.nil (); }
+      void draw          ();
+      void undraw        ();
+      int can_undraw () { return 1; }  // I have the ability to undraw myself.
+      int need_to_clear () { return 0; }  // I know how to undraw myself.
+      void clear () { obj_disp.nil (); }
+
+   private :
+      Objid obj;	// The object we should highlight
+      Objid obj_disp;	// The object that is really highlighted
+   };
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/img.cc	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,271 @@
+/*
+ *	img.cc - Game image object (255 colours + transparency)
+ *	AYM 2000-06-13
+ */
+
+
+/*
+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 "help1.h"
+#include "img.h"
+#include "wadfile.h"
+#include "wads.h"
+
+
+// Holds the private data members
+class Img_priv
+{
+  public:
+    Img_priv () { buf = 0; width = 0; height = 0; opaque = false; }
+    ~Img_priv () { if (buf != 0) delete[] buf; }
+    img_pixel_t *buf;
+    img_dim_t    width;
+    img_dim_t    height;
+    bool         opaque;
+};
+
+
+/*
+ *	Img::Img - default constructor
+ *
+ *	The new image is a null image.
+ */
+Img::Img ()
+{
+  p = new Img_priv;
+}
+
+
+/*
+ *	Img::Img - constructor with dimensions
+ *
+ *	The new image is set to the specified dimensions.
+ */
+Img::Img (img_dim_t width, img_dim_t height, bool opaque)
+{
+  p = new Img_priv;
+  resize (width, height);
+  set_opaque (opaque);
+}
+
+
+/*
+ *	Img::~Img - dtor
+ */
+Img::~Img ()
+{
+  delete p;
+}
+
+
+/*
+ *	Img::is_null - return true iff this is a null image
+ */
+bool Img::is_null () const
+{
+  return p->buf == 0;
+}
+
+
+/*
+ *	Img::width - return the current width
+ *
+ *	If the image is null, return 0.
+ */
+img_dim_t Img::width () const
+{
+  return p->width;
+}
+
+
+/*
+ *	Img::height - return the current height
+ *
+ *	If the image is null, return 0.
+ */
+img_dim_t Img::height () const
+{
+  return p->height;
+}
+
+
+/*
+ *	Img::buf - return a const pointer on the buffer
+ *
+ *	If the image is null, return a null pointer.
+ */
+const img_pixel_t *Img::buf () const
+{
+  return p->buf;
+}
+
+
+/*
+ *	Img::wbuf - return a writable pointer on the buffer
+ *
+ *	If the image is null, return a null pointer.
+ */
+img_pixel_t *Img::wbuf ()
+{
+  return p->buf;
+}
+
+
+/*
+ *	Img::clear - clear the image
+ */
+void Img::clear ()
+{
+  if (p->buf != 0)
+    memset (p->buf, IMG_TRANSP, p->width * p->height);
+}
+
+
+/*
+ *	Img::set_opaque - set or clear the opaque flag
+ */
+void Img::set_opaque (bool opaque)
+{
+  p->opaque = opaque;
+}
+
+ 
+/*
+ *	Img::resize - resize the image
+ *
+ *	If either dimension is zero, the image becomes a null
+ *	image.
+ */
+void Img::resize (img_dim_t width, img_dim_t height)
+{
+  if (width == p->width && height == p->height)
+    return;
+
+  // Unallocate old buffer
+  if (p->buf != 0)
+  {
+    delete[] p->buf;
+    p->buf = 0;
+  }
+
+  // Is it a null image ?
+  if (width == 0 || height == 0)
+  {
+    p->width  = 0;
+    p->height = 0;
+    return;
+  }
+
+  // Allocate new buffer
+  p->width  = width;
+  p->height = height;
+  p->buf = new img_pixel_t[width * height + 10];  // Some slack
+  clear ();
+}
+
+
+/*
+ *	Img::save - save an image to file in packed PPM format
+ *
+ *	Return 0 on success, non-zero on failure
+ *
+ *	If an error occurs, errno is set to:
+ *	- ECHILD if PLAYPAL could not be loaded
+ *	- whatever fopen() or fclose() set it to
+ */
+int Img::save (const char *filename) const
+{
+  int rc = 0;
+  FILE *fp = 0;
+
+  // Load palette 0 from PLAYPAL
+  MDirPtr dir = FindMasterDir (MasterDir, "PLAYPAL");
+  if (dir == 0)
+  {
+    errno = ECHILD;
+    return 1;
+  }
+  unsigned char *pal = new unsigned char[768];
+  dir->wadfile->seek (dir->dir.start);
+  if (dir->wadfile->error ())
+  {
+    /*warn ("%s: can't seek to %lXh\n",
+	dir->wadfile->filename, (unsigned long) ftell (dir->wadfile->fp));
+    warn ("PLAYPAL: seek error\n");*/
+    rc = 1;
+    errno = ECHILD;
+    goto byebye;
+  }
+  dir->wadfile->read_bytes (pal, 768);
+  if (dir->wadfile->error ())
+  {
+    /*warn ("%s: read error", dir->wadfile->where ());
+    warn ("PLAYPAL: read error\n");*/
+    rc = 1;
+    errno = ECHILD;
+    goto byebye;
+  }
+
+  // Create PPM file
+  fp = fopen (filename, "wb");
+  if (fp == NULL)
+  {
+    rc = 1;
+    goto byebye;
+  }
+  fputs ("P6\n", fp);
+  fprintf (fp, "# %s\n", what ());
+  fprintf (fp, "%d %d 255\n", p->width, p->height);
+  {
+    const img_pixel_t *pix    = p->buf;
+    const img_pixel_t *pixmax = pix + (unsigned long) p->width * p->height;
+    for (; pix < pixmax; pix++)
+    {
+      if (*pix == IMG_TRANSP && ! p->opaque)
+      {
+	putc ( 0, fp);	// DeuTex convention, rgb:0/2f/2f
+	putc (47, fp);
+	putc (47, fp);
+      }
+      else
+      {
+	putc (pal[3 * *pix    ], fp);
+	putc (pal[3 * *pix + 1], fp);
+	putc (pal[3 * *pix + 2], fp);
+      }
+    }
+  }
+  if (ferror (fp))
+    rc = 1;
+
+byebye:
+  if (fp != 0)
+    if (fclose (fp))
+      rc = 1;
+  delete[] pal;
+  return rc;
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/img.h	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,45 @@
+/*
+ *	img.h - Game image object (255 colours + transparency)
+ *	AYM 2000-06-13
+ */
+
+
+#ifndef YH_IMG  /* DO NOT INSERT ANYTHING BEFORE THIS LINE */
+#define YH_IMG
+
+
+typedef u8             img_pixel_t;
+typedef unsigned short img_dim_t;
+class Img_priv;
+
+
+/* The colour number used to represent transparent pixels in an
+   Img. Any value will do but zero is probably best
+   performance-wise. */
+const img_pixel_t IMG_TRANSP = 0;
+
+
+class Img
+{
+  public :
+    Img ();
+    Img (img_dim_t width, img_dim_t height, bool opaque);
+    ~Img ();
+    bool               is_null    () const;	// Is it a null image ?
+    img_dim_t          width      () const;	// Return the width
+    img_dim_t          height     () const;	// Return the height
+    const img_pixel_t *buf        () const;	// Return pointer on buffer
+    img_pixel_t       *wbuf       ();		// Return pointer on buffer
+    void               clear      ();
+    void               set_opaque (bool opaque);
+    void               resize     (img_dim_t width, img_dim_t height);
+    int                save       (const char *filename) const;
+    
+  private :
+    Img            (const Img&);	// Too lazy to implement it
+    Img& operator= (const Img&);	// Too lazy to implement it
+    Img_priv *p;
+};
+
+
+#endif  /* DO NOT ADD ANYTHING AFTER THIS LINE */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/imgscale.cc	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,116 @@
+/*
+ *	imgscale.cc
+ *	AYM 2000-06-16
+ */
+
+
+/*
+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 "img.h"
+
+
+/*
+ *	scale_img - scale a game image
+ *
+ *	<img> is the source image, <omg> is the destination
+ *	image. <scale> is the scaling factor (> 1.0 to magnify).
+ *	A scaled copy of <img> is put in <omg>. <img> is not
+ *	modified. Any previous data in <omg> is lost.
+ *
+ *	Example:
+ *
+ *	  Img raw;
+ *	  Img scaled;
+ *	  LoadPicture (raw, ...);
+ *	  scale_img (raw, 2, scaled);
+ *	  display_img (scaled, ...);
+ *
+ *	The implementation is mediocre in the case of scale
+ *	factors < 1 because it uses only one source pixel per
+ *	destination pixel. On certain patterns, it's likely to
+ *	cause a visible loss of quality.
+ *
+ *	In the case of scale factors > 1, the algorithm is
+ *	suboptimal.
+ */
+void scale_img (const Img& img, double scale, Img& omg)
+{
+  img_dim_t iwidth  = img.width ();
+  img_dim_t owidth  = (img_dim_t) (img.width () * scale + 0.5);
+  img_dim_t oheight = (img_dim_t) (img.height () * scale + 0.5);
+  omg.resize (owidth, oheight);
+  const img_pixel_t *const ibuf = img.buf ();
+  img_pixel_t       *const obuf = omg.wbuf ();
+  if (scale <= 2.0)
+  {
+#if 0
+    img_pixel_t *orow = obuf;
+    for (int oy = 0; oy < oheight; oy++)
+    {
+      int iy = (int) (oy / scale);
+      const img_pixel_t *const irow = ibuf + iwidth * iy;
+      for (int ox = 0; ox < owidth; ox++)
+      {
+	int ix = (int) (ox / scale);
+	*orow++ = irow[ix];
+      }
+    }
+#else  // Supposedly faster ?
+    img_pixel_t *orow = obuf;
+    int *ix = new int[owidth];
+    for (int ox = 0; ox < owidth; ox++)
+      ix[ox] = (int) (ox / scale);
+    const int *const ix_end = ix + owidth;
+    for (int oy = 0; oy < oheight; oy++)
+    {
+      int iy = (int) (oy / scale);
+      const img_pixel_t *const irow = ibuf + iwidth * iy;
+      for (const int *i = ix; i < ix_end; i++)
+	*orow++ = irow[*i];
+    }
+    delete[] ix;
+#endif
+  }
+  // (Slightly) optimized version for large zoom factors.
+  else
+  {
+    size_t pixels_at_a_time = (int) (scale + 0.99999999999);
+    int *ox = new int[iwidth];
+    for (int ix = 0; ix < iwidth; ix++)
+      ox[ix] = (int) (ix * scale);
+    for (int oy = 0; oy < oheight; oy++)
+    {
+      int iy = (int) (oy / scale);
+      const img_pixel_t *const irow = ibuf + iwidth * iy;
+      img_pixel_t       *const orow = obuf + owidth * oy;
+      for (int ix = 0; ix < iwidth; ix++)
+	memset (orow + ox[ix], irow[ix], pixels_at_a_time);
+    }
+    fflush (stdout);
+    delete[] ox;
+  }
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/imgscale.h	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,17 @@
+/*
+ *	imgscale.h
+ *	AYM 2000-06-16
+ */
+
+
+#ifndef YH_IMGSCALE  /* DO NOT INSERT ANYTHING BEFORE THIS LINE */
+#define YH_IMGSCALE
+
+
+class Img;
+
+
+void scale_img (const Img& img, double scale, Img& omg);
+
+
+#endif  /* DO NOT ADD ANYTHING AFTER THIS LINE */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/imgspect.cc	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,66 @@
+/*
+ *	imgspect.cc
+ *	AYM 1999-03-09
+ */
+
+
+/*
+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 "img.h"
+#include "imgspect.h"
+
+
+/*
+ *	spectrify_img - make a game image look vaguely like a spectre
+ */
+void spectrify_img (Img& img)
+{
+int x,y;
+u8 grey;
+
+// FIXME this is gross
+if (! strncmp (Game, "doom", 4))
+  grey = 104;
+else if (! strcmp (Game, "heretic"))
+  grey = 8;
+else
+{
+  nf_bug ("spectrifying not defined with this game");
+  return;
+}
+
+img_dim_t width  = img.width ();
+img_dim_t height = img.height ();
+img_pixel_t *buf = img.wbuf ();
+for (y = 0; y < height; y++)
+   {
+   img_pixel_t *row = buf + y * width;
+   for (x = 0; x < width; x++)
+      if (row[x] != IMG_TRANSP)
+         row[x] = grey + (rand () >> 6) % 7;  // FIXME more kludgery
+   }
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/imgspect.h	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,12 @@
+/*
+ *	imgspect.h
+ *	AYM 1999-03-09
+ */
+
+
+class Img;
+
+
+void spectrify_img (Img& img);
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/infobar.cc	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,255 @@
+/*
+ *	infobar.cc
+ *	The infobar_c class.
+ *	AYM 1998-10-10
+ */
+
+
+/*
+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.
+*/
+
+
+/*
+The way the info bar is handled is something of a mess.
+In principle, its various text fields should be widgets in their
+own right. Out of laziness, said text fields are not and can't
+undraw themselves either so the whole box is redrawn everytime one
+of the text fields changes. The "pointer position" field is treated
+specially ; since it changes very often, it can undraw itself.
+*/
+
+
+#include "yadex.h"
+#include "gfx.h"
+#include "infobar.h"
+#include "objid.h"
+
+
+const char infobar_c::FILE_NAME_UNSET[1] = { ' ' };  // A special pointer value 
+const char infobar_c::LEVEL_NAME_UNSET[1] = { ' ' };  // A special pointer value
+
+
+infobar_c::infobar_c ()
+{
+visible               = 0;
+visible_disp          = 0;
+file_name             = 0;
+file_name_disp        = FILE_NAME_UNSET;
+level_name            = 0;
+level_name_disp       = LEVEL_NAME_UNSET;
+obj_type              = OBJ_NONE;
+obj_type_disp         = OBJ_NONE;
+changes               = -1;
+changes_disp          = -1;
+grid_snap             = -1;
+grid_snap_disp        = -1;
+grid_step_locked      = -1;
+grid_step_locked_disp = -1;
+scale                 = -1;
+scale_disp            = -1;
+grid_step             = -1;
+grid_step_disp        = -1;
+flags                 = 0;
+}
+
+
+
+
+void infobar_c::draw ()
+{
+int x;
+int redraw_from_scratch;
+
+x = text_x0;
+
+if (! visible)
+   return;
+
+redraw_from_scratch =
+   visible && ! visible_disp
+   || file_name_disp        != file_name
+   || level_name_disp       != level_name
+   || obj_type_disp         != obj_type
+   || changes_disp          != changes
+   || grid_snap_disp        != grid_snap
+   || grid_step_locked_disp != grid_step_locked
+   || scale_disp            != scale
+   || grid_step_disp        != grid_step;
+
+if (redraw_from_scratch)
+   {
+   DrawScreenBox3D (0, out_y0, ScrMaxX, ScrMaxY);
+   visible_disp = 1;
+   flags &= ~ pointer_disp_set;
+   }
+
+set_colour (WINFG);
+
+// The name of the file being edited.
+{
+int chars;
+if (! file_name)
+   {
+   const char *const msg = "(New level)";
+   if (redraw_from_scratch || file_name_disp != file_name)
+      DrawScreenText (x, text_y0, msg);
+   chars = strlen (msg);
+   }
+else
+   {
+   al_fbase_t filebase;
+   al_fext_t fileext;
+   // FIXME wasteful to do it each time
+   al_fana (file_name, 0, 0, filebase, fileext);
+   if (redraw_from_scratch || file_name_disp != file_name)
+      DrawScreenText (x, text_y0, "%s%s", filebase, fileext);
+   chars = strlen (filebase) + strlen (fileext);
+   }
+x += (chars + 2) * FONTW;
+file_name_disp = file_name;
+}
+
+// The name of the level being edited.
+{
+int chars;
+if (! level_name)
+   {
+   const char *const msg = "(n/s)";
+   if (redraw_from_scratch || level_name_disp != level_name)
+      DrawScreenText (x, text_y0, msg);
+   chars = strlen (msg);
+   }
+else
+   {
+   if (redraw_from_scratch || level_name_disp != level_name)
+      DrawScreenText (x, text_y0, "%.5s", level_name);
+   chars = strlen (level_name);
+   }
+x += (chars + 2) * FONTW;
+level_name_disp = level_name;
+}
+
+// Type of objects being edited.
+if (redraw_from_scratch || obj_type_disp != obj_type)
+   {
+   DrawScreenText (x, text_y0, "%s", GetEditModeName (obj_type));
+   obj_type_disp = obj_type;
+   }
+x += 10 * FONTW;
+
+// Any changes made ?
+if (redraw_from_scratch || changes_disp != changes)
+   {
+   DrawScreenText (x, text_y0, changes > 1 ? "**" : (changes ? "*" : ""));
+   changes_disp = changes;
+   }
+x += 4 * FONTW;
+
+// scale
+if (redraw_from_scratch || scale_disp != scale)
+   {
+#ifdef OLD
+   if (Scale < 1.0)
+      DrawScreenText (x, text_y0, "Scale: 1/%d", (int) (1.0 / Scale + 0.5));
+   else
+      DrawScreenText (x, text_y0, "Scale: %d/1", (int) Scale);
+#else
+   DrawScreenText (x, text_y0, "Scale: %d%%", (int) (Scale * 100));
+#endif
+   scale_disp = scale;
+   }
+x += 13 * FONTW;
+
+// grid_step
+if (redraw_from_scratch || grid_step_disp != grid_step)
+   {
+   DrawScreenText (x, text_y0, "Grid: %d", grid_step);
+   grid_step_disp = grid_step;
+   }
+x += 11 * FONTW;
+
+// grid_step_locked
+if (redraw_from_scratch || grid_step_locked_disp != grid_step_locked)
+   {
+   DrawScreenText (x, text_y0, "%s", grid_step_locked ? "Lock" : "Auto");
+   grid_step_locked_disp = grid_step_locked;
+   }
+x += 6 * FONTW;
+
+// grid_snap
+if (redraw_from_scratch || grid_snap_disp != grid_snap)
+   {
+   DrawScreenText (x, text_y0, "%s", grid_snap ? "Snap" : "Free");
+   grid_snap_disp = grid_snap;
+   }
+x += 6 * FONTW;
+
+#ifdef Y_DOS
+if (farcoreleft () < 50000L)
+   {
+   if (farcoreleft () < 20000L)
+      set_colour (LIGHTRED);
+   else
+      set_colour (RED);
+   }
+DrawScreenText (x, text_y0, "Free mem: %lu", farcoreleft ());
+#endif
+
+// The current pointer coordinates.
+if ((flags & pointer_disp_set)
+   && ! (flags & pointer_set)
+      || pointer_x_disp != pointer_x
+      || pointer_y_disp != pointer_y)
+   {
+   set_colour (WINBG);
+   DrawScreenBox (x, text_y0, x + 14 * FONTW - 1, text_y1);
+   flags &= ~ pointer_disp_set;
+   }
+if ((flags & pointer_set)
+   && ! (flags & pointer_disp_set)
+      || pointer_x_disp != pointer_x
+      || pointer_y_disp != pointer_y)
+   {
+   set_colour (WINFG);
+   /* FIXME pointer_x/y are not significant the first time. */
+   DrawScreenText (x, text_y0, "%5d, %5d", pointer_x, pointer_y);
+   pointer_x_disp = pointer_x;
+   pointer_y_disp = pointer_y;
+   flags |= pointer_disp_set;
+   }
+}
+
+
+void infobar_c::clear ()
+{
+visible_disp          = 0;
+file_name_disp        = FILE_NAME_UNSET;
+level_name_disp       = LEVEL_NAME_UNSET;
+obj_type_disp         = OBJ_NONE;
+changes_disp          = -1;
+grid_snap_disp        = -1;
+grid_step_locked_disp = -1;
+scale_disp            = -1;
+grid_step_disp        = -1;
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/infobar.h	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,145 @@
+/*
+ *	infobar.h
+ *	Info bar
+ *	AYM 1998-10-10
+ */
+
+
+/*
+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 "edwidget.h"
+
+
+class infobar_c : public edwidget_c
+   {
+   public :
+      infobar_c ();
+
+      void set_visible (int visible) { this->visible = visible; }
+
+      void set_file_name (const char *file_name)
+	 { this->file_name = file_name; }
+
+      void set_level_name (const char *level_name)
+	 { this->level_name = level_name; }
+
+      void set_obj_type  (int obj_type)  { this->obj_type = obj_type; }
+      void set_changes   (int changes)   { this->changes = changes; }
+      void set_grid_snap (int grid_snap) { this->grid_snap = grid_snap; }
+
+      void set_grid_step_locked (int grid_step_locked)
+	 { this->grid_step_locked = grid_step_locked; } 
+
+      void set_scale     (float scale)   { this->scale = scale; }
+      void set_grid_step (int grid_step) { this->grid_step = grid_step; }
+
+      void set_pointer (int x, int y)
+	 {
+	 flags |= pointer_set;
+	 pointer_x = x;
+	 pointer_y = y;
+	 }
+
+      void unset_pointer ()
+	 { flags &= ~ pointer_set; }
+
+      /* Methods declared in edwidget_c */
+      void draw ();
+
+      void undraw ()
+         { } // I can't undraw myself
+
+      int can_undraw ()
+         { return 0; }  // I don't have the ability to undraw myself
+
+      int  need_to_clear ()
+         { return visible_disp && ! visible; } // I can't undraw myself
+
+      void clear ();
+
+      int req_width ()
+         { return -1; /* Infinite */ }
+
+      int req_height ()
+         { return 2 * BOX_BORDER + 2 * NARROW_VSPACING + FONTH; }
+
+      void set_x0 (int x0)
+         { out_x0 = x0; text_x0 = x0 + BOX_BORDER + NARROW_HSPACING; }
+
+      void set_y0 (int y0)
+         { out_y0 = y0; text_y0 = y0 + BOX_BORDER + NARROW_VSPACING; }
+
+      void set_x1 (int x1)
+         { out_x1 = x1; text_x1 = x1 - BOX_BORDER - NARROW_HSPACING; }
+
+      void set_y1 (int y1)
+         { out_y1 = y1; text_y1 = y1 - BOX_BORDER - NARROW_VSPACING; }
+
+      int get_x0 () { return out_x0; }
+      int get_y0 () { return out_y0; }
+      int get_x1 () { return out_x1; }
+      int get_y1 () { return out_y1; }
+
+   private :
+      static const char FILE_NAME_UNSET[1];  // A special pointer value 
+      static const char LEVEL_NAME_UNSET[1];  // A special pointer value
+      static const int pointer_set      = 1;
+      static const int pointer_disp_set = 2;
+
+      int visible;
+      int visible_disp;
+      const char *file_name;
+      const char *file_name_disp;
+      const char *level_name;
+      const char *level_name_disp;
+      int obj_type;
+      int obj_type_disp;
+      int changes;
+      int changes_disp;
+      int grid_snap;
+      int grid_snap_disp;
+      int grid_step_locked;
+      int grid_step_locked_disp;
+      float scale;
+      float scale_disp;
+      int grid_step;
+      int grid_step_disp;
+      int pointer_x;
+      int pointer_x_disp;
+      int pointer_y;
+      int pointer_y_disp;
+
+      int out_x0;
+      int out_y0;
+      int out_x1;
+      int out_y1;
+      int text_x0;
+      int text_y0;
+      int text_x1;
+      int text_y1;
+
+      int flags;
+   };
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/input.cc	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,550 @@
+/*
+ *	input.cc
+ *	User input (mouse and keyboard)
+ *	AYM 1998-06-16
+ */
+
+
+/*
+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"
+#ifdef Y_X11
+#include <time.h>	// nanosleep ()
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>  // XLookupString
+#include <X11/keysym.h>
+#include "gfx.h"
+
+
+/* BGI keyboard input :
+altkey (bios(2)) : 0x03 = shift
+                   0x08 = alt
+3bxx F1
+3cxx F2
+3dxx F3
+3fxx F5
+42xx F8
+43xx F9
+44xx F10
+4bxx left
+4dxx right
+48xx up
+50xx down
+47xx home
+4fxx end
+49xx page up
+51xx page down
+52xx ins
+53xx del
+2exx alt-c
+12xx alt-e
+21xx alt-f
+23xx alt-h
+17xx alt-i
+32xx alt-m
+18xx alt-o
+1fxx alt-s
+*/
+
+
+/* This variable needs to be global because get_input_status() is called
+   from different places and some state needs to be saved (shift, ctrl,
+   alt...). I think there should be one instance of this type for each
+   window that can have focus. But one instance for all windows might be
+   enough. Multi-threading (one thread per edit window) is also an
+   issue. Have to think of it. */
+input_status_t is;
+
+
+/*
+ *	init_input_status
+ *	Initialize <is>. Must be called before using <is> or calling
+ *	get_input_status().
+ */
+void init_input_status ()
+{
+is.in_window   = 0;
+is.width       = -1;
+is.height      = 0;
+is.butl        = 0;
+is.butm        = 0;
+is.butr        = 0;
+is.shift       = 0;
+is.ctrl        = 0;
+is.alt         = 0;
+is.scroll_lock = 0;
+}
+
+
+/*
+ *	Static table for get_input_status to convert keysyms to one
+ *	of the YK_-something codes.
+ */
+typedef struct
+   {
+   KeySym ks;
+   inpev_t key;
+   } key_info_t;
+static const key_info_t key_info[] =
+   {
+   { XK_BackSpace,	YK_BACKSPACE	},
+#ifdef XK_ISO_Left_Tab  /* OpenServer 5.0 X11R5 doesn't have XK_ISO_Left_Tab */
+   { XK_ISO_Left_Tab,	YK_BACKTAB	},
+#endif
+   { XK_Delete,		YK_DEL,		},
+   { XK_Down,		YK_DOWN,	},
+   { XK_End,		YK_END,		},
+   { XK_Escape,		YK_ESC,		},
+   { XK_F1,		YK_F1,		},
+   { XK_F2,		YK_F2,		},
+   { XK_F3,		YK_F3,		},
+   { XK_F4,		YK_F4,		},
+   { XK_F5,		YK_F5,		},
+   { XK_F6,		YK_F6,		},
+   { XK_F7,		YK_F7,		},
+   { XK_F8,		YK_F8,		},
+   { XK_F9,		YK_F9,		},
+   { XK_F10,		YK_F10,		},
+   { XK_Home,		YK_HOME,	},
+   { XK_Insert,		YK_INS,		},
+   { XK_Left,		YK_LEFT,	},
+   { XK_Linefeed,	YK_RETURN,	},
+#ifdef XK_Page_Down	/* HP-UX 10 doesn't have XK_Page_Down */
+   { XK_Page_Down,	YK_PD,		},
+#endif
+#ifdef XK_Page_Up	/* HP-UX 10 doesn't have XK_Page_Up */
+   { XK_Page_Up,	YK_PU,		},
+#endif
+   { XK_Return,		YK_RETURN,	},
+   { XK_Right,		YK_RIGHT,	},
+   { XK_Tab,		YK_TAB,		},
+   { XK_Up,		YK_UP,		},
+   };
+
+
+/*
+ *	get_input_status
+ *	Get the next event and update <is> accordingly.
+ *	If no event is available, waits for idle_sleep_ms ms
+ *	and returns (it's used for the autoscroll feature).
+ */
+void get_input_status ()
+{
+XEvent ev;
+
+is.key = 0;
+
+if (! dpy)  /* Sanity check */
+   fatal_error ("get_input_status() called before XOpenDisplay()");
+if (XPending (dpy) == 0)
+   {
+   // No event ? Wait for <idle_sleep_ms> ms before polling again.
+#if defined Y_NANOSLEEP
+   struct timespec treq = { 0, 1000000ul * idle_sleep_ms };
+   struct timespec trem;
+   nanosleep (&treq, &trem);
+#elif defined Y_USLEEP
+   usleep (1000ul * idle_sleep_ms );
+#else
+   ;  // Neither nanosleep() no usleep() so be a CPU hog.
+   // FIXME: if autoscroll is turned off, could as well
+   // call XNextEvent and sleep for good.
+#endif
+   return;
+   }
+
+XNextEvent (dpy, &ev);
+
+switch (ev.type)
+   {
+   /* Exposure */
+   case Expose :
+#if 0
+      printf ("expose: send=%d w=%d x,y=%4d,%4d w,h=%4d,%4d c=%d\n",
+	 (int) ev.xexpose.send_event,
+	 (int) ev.xexpose.window,
+	 (int) ev.xexpose.x,
+	 (int) ev.xexpose.y,
+	 (int) ev.xexpose.width,
+	 (int) ev.xexpose.height,
+	 (int) ev.xexpose.count);
+#endif
+      if (ev.xexpose.window == win && ev.xexpose.count == 0)
+	 is.key = YE_EXPOSE;
+      break;
+
+   /* Resize */
+   case ConfigureNotify :
+#if 0
+      printf ("configure: x,y=%4d,%4d w,h=%4d,%4d\n",
+         (int) ev.xconfigure.x,
+         (int) ev.xconfigure.y,
+         (int) ev.xconfigure.width,
+         (int) ev.xconfigure.height);
+#endif
+      if (is.width < 0 || ev.xconfigure.width != is.width
+		       || ev.xconfigure.height != is.height)
+	 {
+	 is.key    = YE_RESIZE;
+	 is.width  = ev.xconfigure.width;
+	 is.height = ev.xconfigure.height;
+	 }
+      break;
+
+   /* Mouse motion */
+   case EnterNotify :
+      is.key       = YE_ENTER;
+      is.time      = ev.xcrossing.time;
+      is.in_window = 1;
+      // Sanity
+      if (ev.xcrossing.x < 0) nf_bug ("xcrossing.x < 0");  // Paranoia
+      if (ev.xcrossing.y < 0) nf_bug ("xcrossing.y < 0");  // Paranoia
+      is.x = ev.xcrossing.x;
+      is.y = ev.xcrossing.y;
+      break;
+   case LeaveNotify :
+      is.key       = YE_LEAVE;
+      is.time      = ev.xcrossing.time;
+      is.in_window = 0;  /* Should probably "release" buttons */
+      return;
+      break;
+   case MotionNotify :
+      is.key  = YE_MOTION;
+      is.time = ev.xmotion.time;
+      if (ev.xmotion.x < 0) nf_bug ("xmotion.x < 0");  // Paranoia
+      if (ev.xmotion.y < 0) nf_bug ("xmotion.y < 0");  // Paranoia
+      is.x = ev.xmotion.x;
+      is.y = ev.xmotion.y;
+#ifdef DEBUG
+      {
+	static bool first_time = true;
+	static int dxmin = INT_MAX;
+	static int dxmax = INT_MIN;
+	static int dymin = INT_MAX;
+	static int dymax = INT_MIN;
+	static int prevx = 0;
+	static int prevy = 0;
+	bool change = false;
+	if (! first_time)
+	{
+	  int dx = prevx - ev.xmotion.x;
+	  int dy = prevy - ev.xmotion.y;
+
+	  if (dx < dxmin)
+	  {
+	    dxmin = dx;
+	    change = true;
+	  }
+	  if (dx > dxmax)
+	  {
+	    dxmax = dx;
+	    change = true;
+	  }
+	  if (dy < dymin)
+	  {
+	    dymin = dy;
+	    change = true;
+	  }
+	  if (dy > dymax)
+	  {
+	    dymax = dy;
+	    change = true;
+	  }
+	}
+	prevx = ev.xmotion.x;
+	prevy = ev.xmotion.y;
+	first_time = false;
+	if (change)
+	  printf ("Mouse: xmin=%d, xmax=%d, ymin=%d, ymax=%d\n",
+	    dxmin, dxmax, dymin, dymax);
+      }
+#endif
+      // DEBUG
+      break;
+
+   /* Mouse buttons */
+   case ButtonPress :
+   case ButtonRelease :
+      {
+      is.time = ev.xbutton.time;
+      int press = (ev.type == ButtonPress);
+      if (ev.xbutton.button == Button1)
+	 {
+	 is.key = press ? YE_BUTL_PRESS : YE_BUTL_RELEASE;
+	 is.butl = press;
+	 }
+      else if (ev.xbutton.button == Button2)
+	 {
+	 is.key = press ? YE_BUTM_PRESS : YE_BUTM_RELEASE;
+	 is.butm = press;
+	 }
+      else if (ev.xbutton.button == Button3)
+	 {
+	 is.key = press ? YE_BUTR_PRESS : YE_BUTR_RELEASE;
+	 is.butr = press;
+	 }
+      else if (ev.xbutton.button == Button4)
+	 {
+	 is.key = press ? YE_WHEEL_UP : 0;
+	 }
+      else if (ev.xbutton.button == Button5)
+	 {
+	 is.key = press ? YE_WHEEL_DOWN : 0;
+	 }
+      break;
+      }
+
+   /*
+    * Keyboard
+    * FIXME: need to handle NotifyKeymap event as well.
+    */
+   case KeyPress :
+   case KeyRelease :
+      {
+      KeySym ks;
+      int press;
+      unsigned char c;
+      int has_string;
+
+      is.time = ev.xkey.time;
+
+      press = (ev.type == KeyPress);
+
+      /* Convert keycode -> keysym + char. The keysym is useful for keys
+	 such as cursor arrows that don't have an ASCII code. */
+      has_string = XLookupString ((XKeyEvent *) &ev, (char *) &c, 1, &ks, NULL);
+
+      /* The event says that Ctrl, Alt and Shift are not in the state we
+	 thought they were. Don't panic ; it's just that we missed the
+	 modifier key press/release event as it happened when we didn't
+	 have focus. Adjust ourselves. */
+      if (!! (ev.xkey.state & ShiftMask) != is.shift)
+         is.shift = !! (ev.xkey.state & ShiftMask);
+      if (!! (ev.xkey.state & ControlMask) != is.ctrl)
+         is.ctrl = !! (ev.xkey.state & ControlMask);
+      if (!! (ev.xkey.state & Mod1Mask) != is.alt)
+         is.alt = !! (ev.xkey.state & Mod1Mask);
+
+      /* It's a modifier ? Remember its state */
+      switch (ks)
+	 {
+	 case XK_Shift_L:
+	 case XK_Shift_R:
+	    is.shift = press;
+	    break;
+	 case XK_Control_L:
+	 case XK_Control_R:
+	    is.ctrl = press;
+	    break;
+	 case XK_Alt_L:
+	 case XK_Alt_R:
+	 case XK_Meta_L:
+	 case XK_Meta_R:
+	    is.alt = press;
+	    break;
+	 }
+
+      /* Process ordinary keys */
+      if (press)
+	 {
+	 size_t n;
+	 if (has_string)
+	    is.key = c;
+	 for (n = 0; n < sizeof key_info / sizeof *key_info; n++)
+	    if (key_info[n].ks == ks)
+	       {
+	       is.key = key_info[n].key;
+	       break;
+	       }
+	 if (is.key >= YK_ && is.key != YK_BACKTAB && is.shift)
+	    is.key |= YK_SHIFT;
+	 if (is.key >= YK_ && is.ctrl)
+	    is.key |= YK_CTRL;
+	 if (is.key != 0 && is.alt)
+	    is.key |= YK_ALT;
+	 }
+#if 0
+      if (ev.type == KeyPress)
+	 {
+	 printf ("key=%04hXh", is.key);
+	 if (is.key >= 0 && is.key <= UCHAR_MAX && isprint (is.key))
+	    printf (" (%c)", (char) is.key);
+	 putchar ('\n');
+	 }
+#endif
+      break;
+      }
+   }  /* switch (ev.type) */
+}
+
+#endif  /* #ifdef Y_X11 */
+
+
+/*
+ *	has_input_event
+ *	Tells whether there are events in the input queue
+ */
+int has_input_event ()
+{
+XEvent xev;
+if (XCheckMaskEvent (dpy, 0xffffffff, &xev) == True)
+   {
+   XPutBackEvent (dpy, &xev);
+   return 1;
+   }
+return 0;
+}
+
+
+/*
+ *	have_key
+ *	Return 0 if there is no key press in the input queue, <>0 else.
+ *	This is a convenience function to replace bioskey(1).
+ */
+int have_key ()
+{
+return 1;  /* FIXME!! */
+}
+
+
+/*
+ *	get_key
+ *	Wait until the user presses a key and returns its code.
+ *	This is a convenience function to replace bioskey(0).
+ */
+int get_key ()
+{
+do
+   get_input_status ();
+while (! event_is_key (is.key));
+return is.key;
+}
+
+
+/*
+ *	get_key_or_click
+ *	Wait until the user presses a key or clicks the left button.
+ *	In most cases, you should use this and not get_key().
+ */
+void get_key_or_click ()
+{
+do
+   get_input_status ();
+while (! event_is_key (is.key) && is.key != YE_BUTL_PRESS);
+
+is.key = 0;  // FIXME Shouldn't have to do that but EditorLoop() is broken
+}
+
+
+/*
+ *	key_to_string
+ *	Return a string corresponding to the key number k.
+ *	Examples :
+ *	- for k equal to 'a', returns "a",
+ *	- for k equal to YK_ALT + 'a', returns "Alt-a".
+ *	The string returned is guaranteed to have a length <= 50.
+ */
+typedef struct
+   {
+   inpev_t key;
+   const char *string;
+   } key_string_t;
+static const key_string_t key_string[] =
+   {
+   { ' ',               "Space"         },
+   { YK_BACKSPACE, 	"BS"		},
+   { YK_BACKTAB,	"Shift-Tab"	},
+   { YK_DEL,       	"Del"		},
+   { YK_DOWN,      	"Down"		},
+   { YK_END,		"End"		},
+   { YK_ESC,		"Esc"		},
+   { YK_F1,		"F1"		},
+   { YK_F2,		"F2"		},
+   { YK_F3,		"F3"		},
+   { YK_F4,		"F4"		},
+   { YK_F5,		"F5"		},
+   { YK_F6,		"F6"		},
+   { YK_F7,		"F7"		},
+   { YK_F8,		"F8"		},
+   { YK_F9,		"F9"		},
+   { YK_F10,		"F10"		},
+   { YK_HOME,		"Home"		},
+   { YK_INS,		"Ins"		},
+   { YK_LEFT,		"Left"		},
+   { YK_PD,		"Pgdn"		},
+   { YK_PU,		"Pgup"		},
+   { YK_RETURN,		"Return"	},
+   { YK_RIGHT,		"Right"		},
+   { YK_TAB,		"Tab"		},
+   { YK_UP,		"Up"		},
+   };
+
+const char *key_to_string (inpev_t k)
+{
+static char buf[51];
+
+// Is one of the special keys ?
+size_t n;
+const size_t nmax = sizeof key_string / sizeof *key_string;
+for (n = 0; n < nmax; n++)
+   if (key_string[n].key == k)
+      break;
+
+*buf = '\0';
+if (k & YK_CTRL || (n == nmax && k <= 31))
+   {
+   al_saps (buf, "Ctrl-", sizeof buf - 1);
+   if (k & YK_CTRL)
+      k ^= YK_CTRL;
+   if (k <= 31)
+      k += 96;  // Heavy ASCII-ism : 01h (^A) -> 61h ("a")
+   }
+if (k & YK_ALT)
+   {
+   al_saps (buf, "Alt-", sizeof buf - 1);
+   k ^= YK_ALT;
+   }
+if (k & YK_SHIFT)
+   {
+   al_saps (buf, "Shift-", sizeof buf - 1);
+   k ^= YK_SHIFT;
+   }
+
+if (n == nmax)
+   if (k <= UCHAR_MAX && isprint (k))
+      al_sapc (buf, k, sizeof buf - 1);
+   else
+      {
+      al_sapc (buf, al_adigits[(k >> 12) & 15], sizeof buf - 1);
+      al_sapc (buf, al_adigits[(k >>  8) & 15], sizeof buf - 1);
+      al_sapc (buf, al_adigits[(k >>  4) & 15], sizeof buf - 1);
+      al_sapc (buf, al_adigits[(k >>  0) & 15], sizeof buf - 1);
+      }
+else
+   al_saps (buf, key_string[n].string, sizeof buf - 1);
+
+buf[sizeof buf - 1] = '\0';  /* Paranoia */
+return buf;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/input.h	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,133 @@
+/*
+ *	input.h
+ *	User input (mouse and keyboard)
+ *	AYM 1998-06-16
+ */
+
+
+/*
+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.
+*/
+
+
+typedef unsigned short inpev_t;
+typedef struct
+  {
+  // Window events
+  int  width;		// New window width
+  int  height;		// New window height
+  // Mouse events
+  char in_window;	// <>0 iff mouse pointer is in window
+  char butl;		// <>0 iff left mouse button is depressed
+  char butm;		// <>0 iff middle mouse button is depressed
+  char butr;		// <>0 iff right mouse button is depressed
+  int x;		// Mouse pointer position
+  int y;
+  // Keyboard
+  char shift;		// <>0 iff either [Shift] is pressed
+  char ctrl;		// <>0 iff either [Ctrl] is pressed
+  char alt;		// <>0 iff either [Alt]/[Meta] is pressed
+  char scroll_lock;	// Always 0 for the moment
+  // General
+  inpev_t key;		// Code of last event (key, mouse, resize, expose...)
+  unsigned long time;	// Date of event in ms (1)
+  } input_status_t;
+
+/* Notes:
+(1) Defined only for the following events: key, button, motion
+    enter and leave.
+*/
+
+/* Events and key codes */
+const inpev_t YK_BACKSPACE	= '\b';
+const inpev_t YK_TAB		= '\t';
+const inpev_t YK_RETURN		= '\r';
+const inpev_t YK_ESC		= 0x1b;
+const inpev_t YK_DEL		= 0x7f;
+const inpev_t YK_		= 256;
+const inpev_t YK_BACKTAB	= 257;
+const inpev_t YK_DOWN		= 258;
+const inpev_t YK_END		= 259;
+const inpev_t YK_F1		= 260;
+const inpev_t YK_F2		= 261;
+const inpev_t YK_F3		= 262;
+const inpev_t YK_F4		= 263;
+const inpev_t YK_F5		= 264;
+const inpev_t YK_F6		= 265;
+const inpev_t YK_F7		= 266;
+const inpev_t YK_F8		= 267;
+const inpev_t YK_F9		= 268;
+const inpev_t YK_F10		= 269;
+const inpev_t YK_HOME		= 270;
+const inpev_t YK_INS		= 271;
+const inpev_t YK_LEFT		= 272;
+const inpev_t YK_PU		= 273;
+const inpev_t YK_PD		= 274;
+const inpev_t YK_RIGHT		= 275;
+const inpev_t YK_UP		= 276;
+const inpev_t YK__LAST		= 277;  // Marks the end of key events
+
+// Those are not key numbers but window events
+const inpev_t YE_RESIZE		= 278;
+const inpev_t YE_EXPOSE		= 279;
+
+// Those are not key numbers but mouse events
+const inpev_t YE_BUTL_PRESS	= 280;
+const inpev_t YE_BUTL_RELEASE	= 281;
+const inpev_t YE_BUTM_PRESS	= 282;
+const inpev_t YE_BUTM_RELEASE	= 283;
+const inpev_t YE_BUTR_PRESS	= 284;
+const inpev_t YE_BUTR_RELEASE	= 285;
+const inpev_t YE_WHEEL_UP	= 286;	// Negative, normally bound to button 4
+const inpev_t YE_WHEEL_DOWN	= 287;	// Positive, normally bound to button 5
+const inpev_t YE_ENTER		= 288;
+const inpev_t YE_LEAVE		= 289;
+const inpev_t YE_MOTION		= 290;
+
+// Those are not key numbers but application events
+// (i.e. generated internally)
+const inpev_t YE_ZOOM_CHANGED	= 291;
+
+// Those are ORed with the other key numbers :
+const inpev_t YK_SHIFT		= 0x2000;
+const inpev_t YK_CTRL		= 0X4000; 
+const inpev_t YK_ALT		= 0x8000;
+
+/* Defined in input.c -- see the comment there */
+extern input_status_t is;
+
+/* Whether c is an "ordinary" character, that is a printable (non-
+   control) character. We cannot use isprint because its argument
+   must be <= 255 and in considers A0H-FFH non-printable. */
+#define is_ordinary(c) ((c) < 256 && ((c) & 0x60) && (c) != 0x7f)
+
+/* Apply this to is.key to find out whether it contains a key press event. */
+#define event_is_key(n) (((n) & (YK_SHIFT-1)) > 0 && ((n) & (YK_SHIFT-1)) < YK__LAST)
+
+void init_input_status ();
+void get_input_status ();
+int  has_input_event ();
+int  have_key ();
+int  get_key ();
+void get_key_or_click ();
+const char *key_to_string (inpev_t k);
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/l_align.cc	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,410 @@
+/*
+ *	l_align.cc
+ *	Linedef/sidedef texture alignment
+ *	AYM 1998-02-03
+ */
+
+
+/*
+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 "dialog.h"
+#include "entry.h"
+#include "gfx.h"
+#include "levels.h"
+#include "objid.h"
+#include "oldmenus.h"
+#include "selectn.h"
+#include "textures.h"
+
+
+/*
+   get the absolute height from which the textures are drawn
+*/
+
+int GetTextureRefHeight (int sidedef) /* SWAP! */
+{
+int l, sector;
+int otherside = OBJ_NO_NONE;
+
+/* find the sidedef on the other side of the LineDef, if any */
+ObjectsNeeded (OBJ_LINEDEFS, 0);
+for (l = 0; l < NumLineDefs; l++)
+  {
+  if (LineDefs[l].sidedef1 == sidedef)
+    {
+    otherside = LineDefs[l].sidedef2;
+    break;
+    }
+  if (LineDefs[l].sidedef2 == sidedef)
+    {
+    otherside = LineDefs[l].sidedef1;
+    break;
+    }
+  }
+/* get the Sector number */
+ObjectsNeeded (OBJ_SIDEDEFS, 0);
+sector = SideDefs[sidedef].sector;
+/* if the upper texture is displayed,
+   then the reference is taken from the other Sector */
+if (otherside >= 0)
+  {
+  l = SideDefs[otherside].sector;
+  if (l > 0)
+    {
+    ObjectsNeeded (OBJ_SECTORS, 0);
+    if (Sectors[l].ceilh < Sectors[sector].ceilh
+     && Sectors[l].ceilh > Sectors[sector].floorh)
+      sector = l;
+    }
+  }
+/* return the altitude of the ceiling */
+ObjectsNeeded (OBJ_SECTORS, 0);
+if (sector >= 0)
+  return Sectors[sector].ceilh; /* textures are drawn from the ceiling down */
+else
+  return 0; /* yuck! */
+}
+
+
+
+
+/*
+   Align all textures for the given SideDefs
+
+   Note from RQ:
+      This function should be improved!
+      But what should be improved first is the way the SideDefs are selected.
+      It is stupid to change both sides of a wall when only one side needs
+      to be changed.  But with the current selection method, there is no
+      way to select only one side of a two-sided wall.
+*/
+
+void AlignTexturesY (SelPtr *sdlist) /* SWAP! */
+{
+int h, refh;
+
+if (! *sdlist)
+   return;
+
+/* get the reference height from the first sidedef */
+refh = GetTextureRefHeight ((*sdlist)->objnum);
+ObjectsNeeded (OBJ_SIDEDEFS, 0);
+SideDefs[(*sdlist)->objnum].yoff = 0;
+UnSelectObject (sdlist, (*sdlist)->objnum);
+
+/* adjust Y offset in all other SideDefs */
+while (*sdlist)
+  {
+  h = GetTextureRefHeight ((*sdlist)->objnum);
+  ObjectsNeeded (OBJ_SIDEDEFS, 0);
+  SideDefs[(*sdlist)->objnum].yoff = (refh - h) % 128;
+  UnSelectObject (sdlist, (*sdlist)->objnum);
+  }
+MadeChanges = 1;
+}
+
+
+
+/*
+   Function is to align all highlighted textures in the X-axis
+
+   Note from RJH:
+   LineDefs highlighted are read off in reverse order of highlighting.
+   The '*sdlist' is in the reverse order of the above mentioned LineDefs
+   i.e. the first linedef sidedefs you highlighted will be processed first.
+
+   Note from RQ:
+   See also the note for the previous function.
+
+   Note from RJH:
+   For the menu for aligning textures 'X' NOW operates upon the fact that
+   ALL the SIDEDEFS from the selected LINEDEFS are in the *SDLIST, 2nd
+   sidedef is first, 1st sidedef is 2nd). Aligning textures X now does
+   SIDEDEF 1's and SIDEDEF 2's.  If the selection process is changed,
+   the following needs to be altered radically.
+*/
+
+void AlignTexturesX (SelPtr *sdlist) /* SWAP! */
+{
+			/* FIRST texture name used in the highlited objects */
+char texname[WAD_TEX_NAME + 1];
+char errormessage[80];	/* area to hold the error messages produced */
+int  ldef;		/* linedef number */
+int  sd1;		/* current sidedef in *sdlist */
+int  vert1, vert2;	/* vertex 1 and 2 for the linedef under scrutiny */
+int  xoffset;		/* xoffset accumulator */
+int  useroffset;	/* user input offset for first input */
+i16  texlength;		/* the length of texture to format to */
+int  length;		/* length of linedef under scrutiny */
+i16  dummy;		/* holds useless data */
+int  type_off;		/* do we have an initial offset to use */
+int  type_tex;		/* do we check for same textures */
+int  type_sd;		/* do we align sidedef 1 or sidedef 2 */
+
+type_sd  = 0;		/* which sidedef to align, 1=SideDef1, 2=SideDef2 */
+type_tex = 0;		/* do we test for similar textures, 0 = no, 1 = yes */
+type_off = 0;		/* do we have an inital offset, 0 = no, 1 = yes */
+
+vert1   = -1;
+vert2   = -1;		/* 1st time round the while loop the -1 value is needed */
+texlength  = 0;
+xoffset    = 0;
+useroffset = 0;
+
+switch (vDisplayMenu (250, 110, "Aligning textures (X offset) :",
+
+	" Sidedef 1, Check for identical textures.     ", YK_, 0,
+	" Sidedef 1, As above, but with inital offset. ", YK_, 0,
+	" Sidedef 1, No texture checking.              ", YK_, 0,
+	" Sidedef 1, As above, but with inital offset. ", YK_, 0,
+
+	" Sidedef 2, Check for identical textures.     ", YK_, 0,
+	" Sidedef 2, As above, but with inital offset. ", YK_, 0,
+	" Sidedef 2, No texture checking.              ", YK_, 0,
+	" Sidedef 2, As above, but with inital offset. ", YK_, 0,
+	NULL))
+  {
+  case 1:       /* Sidedef 1 with checking for same textures   */
+    type_sd = 1; type_tex = 1; type_off = 0;
+    break;
+
+  case 2:       /* Sidedef 1 as above, but with inital offset  */
+    type_sd = 1; type_tex = 1; type_off = 1;
+    break;
+
+  case 3:       /* Sidedef 1 regardless of same textures       */
+    type_sd = 1; type_tex = 0; type_off = 0;
+    break;
+
+  case 4:       /* Sidedef 1 as above, but with inital offset  */
+    type_sd = 1; type_tex = 0; type_off = 1;
+    break;
+
+  case 5:       /* Sidedef 2 with checking for same textures   */
+    type_sd = 2; type_tex = 1; type_off = 0;
+    break;
+
+  case 6:       /* Sidedef 2 as above, but with initial offset */
+    type_sd = 2; type_tex = 1; type_off = 1;
+    break;
+
+  case 7:       /* Sidedef 2 regardless of same textures       */
+    type_sd = 2; type_tex = 0; type_off = 0;
+    break;
+
+  case 8:       /* Sidedef 2 as above, but with initial offset */
+    type_sd = 2; type_tex = 0; type_off = 1;
+    break;
+  }
+
+ldef = 0;
+if (! *sdlist)
+   {
+   Notify (-1, -1, "Error in AlignTexturesX: list is empty", 0);
+   return;
+   }
+sd1 = (*sdlist)->objnum;
+
+if (type_sd == 1) /* throw out all 2nd SideDefs untill a 1st is found */
+  {
+  while (*sdlist && LineDefs[ldef].sidedef1!=sd1 && ldef<=NumLineDefs)
+    {
+    ldef++;
+    if (LineDefs[ldef].sidedef2 == sd1)
+      {
+      UnSelectObject (sdlist, (*sdlist)->objnum);
+      if (! *sdlist)
+         return;
+      sd1 = (*sdlist)->objnum;
+      ldef = 0;
+      }
+    }
+  }
+
+if (type_sd == 2) /* throw out all 1st SideDefs untill a 2nd is found */
+  {
+  while (LineDefs[ldef].sidedef2!=sd1 && ldef<=NumLineDefs)
+    {
+    ldef++;
+    if (LineDefs[ldef].sidedef1 == sd1)
+      {
+      UnSelectObject (sdlist, (*sdlist)->objnum);
+      if (! *sdlist)
+	 return;
+      sd1 = (*sdlist)->objnum;
+      ldef = 0;
+      }
+    }
+  }
+
+ObjectsNeeded (OBJ_SIDEDEFS, 0);
+
+/* get texture name of the sidedef in the *sdlist) */
+strncpy (texname, SideDefs[(*sdlist)->objnum].tex3, WAD_TEX_NAME);
+
+/* test if there is a texture there */
+if (texname[0] == '-')
+  {
+  Beep ();
+  sprintf (errormessage, "No texture for sidedef #%d.", (*sdlist)->objnum);
+  Notify (-1, -1, errormessage, 0);
+  return;
+  }
+
+GetWallTextureSize (&texlength, &dummy, texname); /* clunky, but it works */
+
+/* get initial offset to use (if required) */
+if (type_off == 1)    /* source taken from InputObjectNumber */
+   {
+   int  x0;          /* left hand (x) window start     */
+   int  y0;          /* top (y) window start           */
+   int  key;         /* holds value returned by InputInteger */
+   char prompt[80];  /* prompt for inital offset input */
+
+   HideMousePointer ();
+
+   sprintf (prompt, "Enter initial offset between 0 and %d:", (int) texlength);
+
+   x0 = (ScrMaxX - 25 - 8 * strlen (prompt)) / 2;
+   y0 = (ScrMaxY - 55) / 2;
+
+   DrawScreenBox3D (x0, y0, x0 + 25 + 8 * strlen (prompt), y0 + 55);
+   set_colour (WHITE);
+   DrawScreenText (x0 + 10, y0 + 8, prompt);
+
+   while  ((key=InputInteger (x0+10, y0+28, &useroffset, 0, (int) texlength))
+	    != YK_RETURN && key != YK_ESC)
+      Beep ();
+
+   ShowMousePointer ();
+   }
+
+while (*sdlist)  /* main processing loop */
+   {
+   ldef = 0;
+   sd1 = (*sdlist)->objnum;
+
+   if (type_sd == 1) /* throw out all 2nd SideDefs untill a 1st is found */
+   {
+     while (LineDefs[ldef].sidedef1!=sd1 && ldef<=NumLineDefs)
+       {
+       ldef++;
+       if (LineDefs[ldef].sidedef2 == sd1)
+	 {
+	 UnSelectObject (sdlist, (*sdlist)->objnum);
+	 sd1 = (*sdlist)->objnum;
+	 ldef = 0;
+	 if (! *sdlist)
+	    return;
+	 }
+       }
+     }
+
+   if (type_sd == 2) /* throw out all 1st SideDefs untill a 2nd is found */
+     {
+     while (LineDefs[ldef].sidedef2!=sd1 && ldef<=NumLineDefs)
+       {
+       ldef++;
+       if (LineDefs[ldef].sidedef1 == sd1)
+	 {
+	 UnSelectObject (sdlist, (*sdlist)->objnum);
+	 sd1 = (*sdlist)->objnum;
+	 ldef = 0;
+	 if (! *sdlist)
+	    return;
+	 }
+       }
+     }
+
+   /* do we test for same textures for the sidedef in question?? */
+   if (type_tex == 1)
+     {
+     ObjectsNeeded (OBJ_SIDEDEFS, 0);
+     if (strncmp (SideDefs[(*sdlist)->objnum].tex3, texname,WAD_TEX_NAME))
+       {
+       Beep ();
+       sprintf (errormessage, "No texture for sidedef #%d.", (*sdlist)->objnum);
+       Notify (-1, -1, errormessage, 0);
+       return;
+       }
+     }
+
+   sd1 = (*sdlist)->objnum;
+   ldef = 0;
+
+   ObjectsNeeded (OBJ_LINEDEFS,0);
+
+   /* find out which linedef holds that sidedef */
+   if (type_sd == 1)
+     {
+     while (LineDefs[ldef].sidedef1 != sd1 && ldef < NumLineDefs)
+	ldef++;
+     }
+   else
+     {
+     while (LineDefs[ldef].sidedef2 != sd1 && ldef < NumLineDefs)
+       ldef++;
+     }
+
+   vert1 = LineDefs[ldef].start;
+   /* test for linedef highlight continuity */
+   if (vert1 != vert2 && vert2 != -1)
+     {
+     Beep ();
+     sprintf (errormessage, "Linedef #%d is not contiguous"
+       " with the previous linedef, please reselect.", (*sdlist)->objnum);
+     Notify (-1, -1, errormessage, 0);
+     return;
+     }
+   /* is this the first time round here */
+   if (vert1 != vert2)
+     {
+     if (type_off == 1)  /* do we have an initial offset ? */
+       {
+       SideDefs[sd1].xoff = useroffset;
+       xoffset = useroffset;
+       }
+     else
+	SideDefs[sd1].xoff = 0;
+     }
+   else     /* put new xoffset into the sidedef */
+     SideDefs[sd1].xoff = xoffset;
+
+   /* calculate length of linedef */
+   vert2 = LineDefs[ldef].end;
+   ObjectsNeeded (OBJ_VERTICES, 0);
+   length = ComputeDist (Vertices[vert2].x - Vertices[vert1].x,
+			 Vertices[vert2].y - Vertices[vert1].y);
+
+   xoffset += length;
+   /* remove multiples of texlength from xoffset */
+   xoffset = xoffset % texlength;
+   /* move to next object in selected list */
+   UnSelectObject (sdlist, (*sdlist)->objnum);
+   }
+MadeChanges = 1;
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/l_centre.cc	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,73 @@
+/*
+ *	l_centre.cc
+ *	AYM 1998-11-22
+ */
+
+
+/*
+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 "bitvec.h"
+#include "l_centre.h"
+#include "l_vertices.h"
+#include "levels.h"
+
+
+/*
+ *	centre_of_linedefs
+ *	Return the coordinates of the centre of a group of linedefs.
+ */
+void centre_of_linedefs (SelPtr list, int *x, int *y)
+{
+bitvec_c *vertices;
+int nitems;
+long x_sum;
+long y_sum;
+int n;
+
+vertices = bv_vertices_of_linedefs (list);
+x_sum = 0;
+y_sum = 0;
+nitems = 0;
+for (n = 0; n < NumVertices; n++)
+   if (vertices->get (n))
+      {
+      x_sum += Vertices[n].x;
+      y_sum += Vertices[n].y;
+      nitems++;
+      }
+if (nitems == 0)
+   {
+   *x = 0;
+   *y = 0;
+   }
+else
+   {
+   *x = (int) (x_sum / nitems);
+   *y = (int) (y_sum / nitems);
+   }
+delete vertices;
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/l_centre.h	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,9 @@
+/*
+ *	l_centre.h
+ *	AYM 1998-11-22
+ */
+
+
+void centre_of_linedefs (SelPtr list, int *x, int *y);
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/l_flags.cc	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,68 @@
+/*
+ *	l_flags.cc
+ *	AYM 1998-12-21
+ */
+
+
+/*
+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 "levels.h"
+#include "selectn.h"
+#include "wstructs.h"
+
+
+/*
+ *	frob_linedefs_flags
+ *	For all the linedefs in <list>, apply the operator <op>
+ *	with the operand <operand> on the flags field.
+ */
+void frob_linedefs_flags (SelPtr list, int op, int operand)
+{
+  SelPtr cur;
+  i16 mask;
+
+  if (op == YO_CLEAR || op == YO_SET || op == YO_TOGGLE)
+    mask = 1 << operand;
+  else
+    mask = operand;
+
+  for (cur = list; cur; cur = cur->next)
+  {
+    if (op == YO_CLEAR)
+      LineDefs[cur->objnum].flags &= ~mask;
+    else if (op == YO_SET)
+      LineDefs[cur->objnum].flags |= mask;
+    else if (op == YO_TOGGLE)
+      LineDefs[cur->objnum].flags ^= mask;
+    else
+    {
+      nf_bug ("frob_linedef_flags: op=%02X", op);
+      return;
+    }
+  }
+  MadeChanges = 1;
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/l_flags.h	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,9 @@
+/*
+ *	l_flags.h
+ *	AYM 1998-12-22
+ */
+
+
+void frob_linedefs_flags (SelPtr list, int op, int operand);
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/l_misc.cc	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,238 @@
+/*
+ *	l_misc.c
+ *	Linedef/sidedef misc operations.
+ *	AYM 1998-02-03
+ */
+
+
+/*
+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 "levels.h"
+#include "objects.h"
+#include "objid.h"
+#include "selectn.h"
+#include <math.h>
+
+
+static void SliceLinedef (int linedefno, int times);
+
+
+/*
+   flip one or several LineDefs
+*/
+
+void FlipLineDefs ( SelPtr obj, bool swapvertices) /* SWAP! */
+{
+SelPtr cur;
+int    tmp;
+
+ObjectsNeeded ( OBJ_LINEDEFS, 0);
+for (cur = obj; cur; cur = cur->next)
+{
+   if (swapvertices)
+   {
+      /* swap starting and ending Vertices */
+      tmp = LineDefs[ cur->objnum].end;
+      LineDefs[ cur->objnum].end = LineDefs[ cur->objnum].start;
+      LineDefs[ cur->objnum].start = tmp;
+   }
+   /* swap first and second SideDefs */
+   tmp = LineDefs[ cur->objnum].sidedef1;
+   LineDefs[ cur->objnum].sidedef1 = LineDefs[ cur->objnum].sidedef2;
+   LineDefs[ cur->objnum].sidedef2 = tmp;
+}
+MadeChanges = 1;
+MadeMapChanges = 1;
+}
+
+
+/*
+   split one or more LineDefs in two, adding new Vertices in the middle
+*/
+
+void SplitLineDefs ( SelPtr obj) /* SWAP! */
+{
+SelPtr cur;
+int    vstart, vend;
+
+ObjectsNeeded ( OBJ_LINEDEFS, 0);
+for (cur = obj; cur; cur = cur->next)
+  {
+  vstart = LineDefs[cur->objnum].start;
+  vend   = LineDefs[cur->objnum].end;
+  SliceLinedef (cur->objnum, 1);
+  Vertices[NumVertices-1].x = (Vertices[vstart].x + Vertices[vend].x) / 2;
+  Vertices[NumVertices-1].y = (Vertices[vstart].y + Vertices[vend].y) / 2;
+  }
+MadeChanges = 1;
+MadeMapChanges = 1;
+}
+
+
+/*
+ *	MakeRectangularNook - Make a nook or boss in a wall
+ *	
+ *	Before :		After :
+ *					^-->
+ *					|  |
+ *	+----------------->     +------->  v------->
+ *	    1st sidedef             1st sidedef
+ *
+ *	The length of the sides of the nook is sidelen.
+ *	This is true when convex is false. If convex is true, the nook
+ *	is actually a bump when viewed from the 1st sidedef.
+ */
+void MakeRectangularNook (SelPtr obj, int width, int depth, int convex) /* SWAP! */
+{
+SelPtr cur;
+
+ObjectsNeeded (OBJ_LINEDEFS, 0);
+for (cur = obj; cur; cur = cur->next)
+  {
+  int vstart, vend;
+  int x0;
+  int y0;
+  int dx0, dx1, dx2;
+  int dy0, dy1, dy2;
+  int line_len;
+  double real_width;
+  double angle;
+
+  vstart = LineDefs[cur->objnum].start;
+  vend   = LineDefs[cur->objnum].end;
+  x0     = Vertices[vstart].x;
+  y0     = Vertices[vstart].y;
+  dx0    = Vertices[vend].x - x0;
+  dy0    = Vertices[vend].y - y0;
+
+  /* First split the line 4 times */
+  SliceLinedef (cur->objnum, 4);
+
+  /* Then position the vertices */
+  angle  = atan2 (dy0, dx0);
+ 
+  /* If line to split is not longer than sidelen,
+     force sidelen to 1/3 of length */
+  line_len   = ComputeDist (dx0, dy0);
+  real_width = line_len > width ? width : line_len / 3;
+    
+  dx2 = (int) (real_width * cos (angle));
+  dy2 = (int) (real_width * sin (angle));
+
+  dx1 = (dx0 - dx2) / 2;
+  dy1 = (dy0 - dy2) / 2;
+
+  {
+  double normal = convex ? angle-HALFPI : angle+HALFPI;
+  Vertices[NumVertices-1-3].x = x0 + dx1;
+  Vertices[NumVertices-1-3].y = y0 + dy1;
+  Vertices[NumVertices-1-2].x = x0 + dx1 + (int) (depth * cos (normal));
+  Vertices[NumVertices-1-2].y = y0 + dy1 + (int) (depth * sin (normal));
+  Vertices[NumVertices-1-1].x = x0 + dx1 + dx2 + (int) (depth * cos (normal));
+  Vertices[NumVertices-1-1].y = y0 + dy1 + dy2 + (int) (depth * sin (normal));
+  Vertices[NumVertices-1  ].x = x0 + dx1 + dx2;
+  Vertices[NumVertices-1  ].y = y0 + dy1 + dy2;
+  }
+
+  MadeChanges = 1;
+  MadeMapChanges = 1;
+  }
+}
+
+
+/*
+ *	SliceLinedef - Split a linedef several times
+ *
+ *	Splits linedef no. <linedefno> <times> times.
+ *	Side-effects : creates <times> new vertices, <times> new
+ *	linedefs and 0, <times> or 2*<times> new sidedefs.
+ *	The new vertices are put at (0,0).
+ *	See SplitLineDefs() and MakeRectangularNook() for example of use.
+ */
+static void SliceLinedef (int linedefno, int times)
+{
+int prev_ld_no;
+for (prev_ld_no = linedefno; times > 0; times--, prev_ld_no = NumLineDefs-1)
+  {
+  int sd;
+
+  InsertObject (OBJ_VERTICES, -1, 0, 0);
+  InsertObject (OBJ_LINEDEFS, linedefno, 0, 0);
+  LineDefs[NumLineDefs-1].start = NumVertices - 1;
+  LineDefs[NumLineDefs-1].end   = LineDefs[prev_ld_no].end;
+  LineDefs[prev_ld_no   ].end   = NumVertices - 1;
+  
+  sd = LineDefs[linedefno].sidedef1;
+  if (sd >= 0)
+    {
+    InsertObject (OBJ_SIDEDEFS, sd, 0, 0);
+    ObjectsNeeded (OBJ_LINEDEFS, 0);
+    LineDefs[NumLineDefs-1].sidedef1 = NumSideDefs - 1;
+    }
+  sd = LineDefs[linedefno].sidedef2;
+  if (sd >= 0)
+    {
+    InsertObject (OBJ_SIDEDEFS, sd, 0, 0);
+    ObjectsNeeded (OBJ_LINEDEFS, 0);
+    LineDefs[NumLineDefs-1].sidedef2 = NumSideDefs - 1;
+    }
+  }
+}
+
+
+/*
+ *	SetLinedefLength
+ *	Move either vertex to set length of linedef to desired value
+ */
+void SetLinedefLength (SelPtr obj, int length, int move_2nd_vertex)
+{
+SelPtr cur;
+
+ObjectsNeeded (OBJ_LINEDEFS, 0);
+for (cur = obj; cur; cur = cur->next)
+  {
+  VPtr vertex1 = Vertices + LineDefs[cur->objnum].start;
+  VPtr vertex2 = Vertices + LineDefs[cur->objnum].end;
+  double angle = atan2 (vertex2->y - vertex1->y, vertex2->x - vertex1->x);
+  int dx       = (int) (length * cos (angle));
+  int dy       = (int) (length * sin (angle));
+
+  if (move_2nd_vertex)
+    {
+    vertex2->x = vertex1->x + dx;
+    vertex2->y = vertex1->y + dy;
+    }
+  else
+    {
+    vertex1->x = vertex2->x - dx;
+    vertex1->y = vertex2->y - dy;
+    }
+
+  MadeChanges = 1;
+  MadeMapChanges = 1;
+  }
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/l_prop.cc	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,549 @@
+/*
+ *	l_prop.c
+ *	Linedefs properties
+ *	Some of this was originally in editobj.c. It was moved here to
+ *	improve overlay granularity (therefore memory consumption).
+ *	AYM 1998-02-07
+ */
+
+
+/*
+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 "entry.h"
+#include "gfx.h"
+#include "levels.h"
+#include "menudata.h"
+#include "objects.h"
+#include "objid.h"
+#include "oldmenus.h"
+#include "game.h"
+#include "selectn.h"
+#include "textures.h"
+
+
+/*
+ *	Menu_data_ldt - Menu_data class for the linedef type
+ */
+class Menu_data_ldt : public Menu_data
+{
+  public :
+    Menu_data_ldt (al_llist_t *list);
+    virtual size_t nitems () const;
+    virtual const char *operator[] (size_t n) const;
+
+  private :
+    mutable char buf[100];
+    al_llist_t *list;
+};
+
+
+/*
+ *	Menu_data_ldt::Menu_data_ldt - ctor
+ */
+Menu_data_ldt::Menu_data_ldt (al_llist_t *list) : list (list)
+{
+  al_lrewind (this->list);
+}
+
+
+/*
+ *	Menu_data_ldt::nitems - return the number of items
+ */
+size_t Menu_data_ldt::nitems () const
+{
+  return al_lcount (list);
+}
+
+
+/*
+ *	Menu_data_ldt::operator[] - return the nth item
+ */
+const char *Menu_data_ldt::operator[] (size_t n) const
+{
+  if (al_lseek (list, n, SEEK_SET) != 0)
+  {
+    sprintf (buf, "BUG: al_lseek(%p, %lu): %s",
+      (void *) list, 
+      (unsigned long) n,
+      al_astrerror (al_aerrno));
+    return buf;
+  }
+  const ldtdef_t **pptr = (const ldtdef_t **) al_lptr (list);
+  if (pptr == NULL)
+    sprintf (buf, "BUG: al_lptr(%p): %s",
+      (void *) list,
+      al_astrerror (al_aerrno));
+  else
+    sprintf (buf, "%3d - %.70s", (*pptr)->number, (*pptr)->longdesc);
+  return buf;
+}
+
+
+/*
+ *	Prototypes of private functions
+ */
+static char *GetTaggedLineDefFlag (int linedefnum, int flagndx);
+static int InputLinedefType (int x0, int y0, int *number);
+static const char *PrintLdtgroup (void *ptr);
+
+
+void LinedefProperties (int x0, int y0, SelPtr obj)
+{
+  char  *menustr[8];
+  char   texname[WAD_TEX_NAME + 1];
+  int    n, val;
+  SelPtr cur, sdlist;
+  int objtype = OBJ_LINEDEFS;
+  int    subwin_y0;
+  int    subsubwin_y0;
+
+  {
+    bool sd1 = LineDefs[obj->objnum].sidedef1 >= 0;
+    bool sd2 = LineDefs[obj->objnum].sidedef2 >= 0;
+    val = vDisplayMenu (x0, y0, "Choose the object to edit:",
+       "Edit the linedef",					YK_, 0,
+       sd1 ? "Edit the 1st sidedef" : "Add a 1st sidedef",	YK_, 0,
+       sd2 ? "Edit the 2nd sidedef" : "Add a 2nd sidedef",	YK_, 0,
+       NULL);
+  }
+  subwin_y0 = y0 + BOX_BORDER + (2 + val) * FONTH;
+  switch (val)
+  {
+    case 1:
+      for (n = 0; n < 8; n++)
+	menustr[n] = (char *) GetMemory (60);
+      sprintf (menustr[7], "Edit linedef #%d", obj->objnum);
+      sprintf (menustr[0], "Change flags            (Current: %d)",
+	LineDefs[obj->objnum].flags);
+      sprintf (menustr[1], "Change type             (Current: %d)",
+	LineDefs[obj->objnum].type);
+      sprintf (menustr[2], "Change sector tag       (Current: %d)",
+	LineDefs[obj->objnum].tag);
+      sprintf (menustr[3], "Change starting vertex  (Current: #%d)",
+	LineDefs[obj->objnum].start);
+      sprintf (menustr[4], "Change ending vertex    (Current: #%d)",
+	LineDefs[obj->objnum].end);
+      sprintf (menustr[5], "Change 1st sidedef ref. (Current: #%d)",
+	LineDefs[obj->objnum].sidedef1);
+      sprintf (menustr[6], "Change 2nd sidedef ref. (Current: #%d)",
+	LineDefs[obj->objnum].sidedef2);
+      val = vDisplayMenu (x0 + 42, subwin_y0, menustr[7],
+	menustr[0], YK_, 0,
+	menustr[1], YK_, 0,
+	menustr[2], YK_, 0,
+	menustr[3], YK_, 0,
+	menustr[4], YK_, 0,
+	menustr[5], YK_, 0,
+	menustr[6], YK_, 0,
+	NULL);
+      for (n = 0; n < 8; n++)
+	FreeMemory (menustr[n]);
+      subsubwin_y0 = subwin_y0 + BOX_BORDER + (2 + val) * FONTH;
+      switch (val)
+      {
+	case 1:
+	  val = vDisplayMenu (x0 + 84, subsubwin_y0, "Toggle the flags:",
+	    GetTaggedLineDefFlag (obj->objnum, 1),  YK_, 0,
+	    GetTaggedLineDefFlag (obj->objnum, 2),  YK_, 0,
+	    GetTaggedLineDefFlag (obj->objnum, 3),  YK_, 0,
+	    GetTaggedLineDefFlag (obj->objnum, 4),  YK_, 0,
+	    GetTaggedLineDefFlag (obj->objnum, 5),  YK_, 0,
+	    GetTaggedLineDefFlag (obj->objnum, 6),  YK_, 0,
+	    GetTaggedLineDefFlag (obj->objnum, 7),  YK_, 0,
+	    GetTaggedLineDefFlag (obj->objnum, 8),  YK_, 0,
+	    GetTaggedLineDefFlag (obj->objnum, 9),  YK_, 0,
+	    GetTaggedLineDefFlag (obj->objnum, 10), YK_, 0,
+	    GetTaggedLineDefFlag (obj->objnum, 11), YK_, 0,
+	    GetTaggedLineDefFlag (obj->objnum, 12), YK_, 0,
+	    GetTaggedLineDefFlag (obj->objnum, 13), YK_, 0,
+	    GetTaggedLineDefFlag (obj->objnum, 14), YK_, 0,
+	    GetTaggedLineDefFlag (obj->objnum, 15), YK_, 0,
+	    GetTaggedLineDefFlag (obj->objnum, 16), YK_, 0,
+	    "(Enter a decimal value)", YK_, 0,
+	    NULL);
+	  if (val >= 1 && val <= 16)
+	     {
+	     for (cur = obj; cur; cur = cur->next)
+		LineDefs[cur->objnum].flags ^= 0x01 << (val - 1);
+	     MadeChanges = 1;
+	     }
+	  else if (val == 17)
+	     {
+	     val = InputIntegerValue (x0 + 126, subsubwin_y0 + 12 * FONTH,
+		0, 65535, LineDefs[obj->objnum].flags);
+	     if (val != IIV_CANCEL)
+		{
+		for (cur = obj; cur; cur = cur->next)
+		   LineDefs[cur->objnum].flags = val;
+		MadeChanges = 1;
+		}
+	     }
+	  break;
+
+	case 2:
+	  if (! InputLinedefType (x0, subsubwin_y0, &val))
+	  {
+	    for (cur = obj; cur; cur = cur->next)
+	      LineDefs[cur->objnum].type = val;
+	    MadeChanges = 1;
+	  }
+	  break;
+
+	case 3:
+	  val = InputIntegerValue (x0 + 84, subsubwin_y0,
+	    -32768, 32767, LineDefs[obj->objnum].tag);
+	  if (val != IIV_CANCEL)  // Not [esc]
+	  {
+	    for (cur = obj; cur; cur = cur->next)
+	      LineDefs[cur->objnum].tag = val;
+	    MadeChanges = 1;
+	  }
+	  break;
+
+	case 4:
+	  val = InputObjectXRef (x0 + 84, subsubwin_y0,
+	    OBJ_VERTICES, 0, LineDefs[obj->objnum].start);
+	  if (val >= 0)
+	  {
+	    for (cur = obj; cur; cur = cur->next)
+	      LineDefs[cur->objnum].start = val;
+	    MadeChanges = 1;
+	    MadeMapChanges = 1;
+	  }
+	  break;
+
+	case 5:
+	  val = InputObjectXRef (x0 + 84, subsubwin_y0,
+	    OBJ_VERTICES, 0, LineDefs[obj->objnum].end);
+	  if (val >= 0)
+	  {
+	    for (cur = obj; cur; cur = cur->next)
+	      LineDefs[cur->objnum].end = val;
+	    MadeChanges = 1;
+	    MadeMapChanges = 1;
+	  }
+	  break;
+
+	case 6:
+	  val = InputObjectXRef (x0 + 84, subsubwin_y0,
+	    OBJ_SIDEDEFS, 1, LineDefs[obj->objnum].sidedef1);
+	  if (val >= -1)
+	  {
+	    for (cur = obj; cur; cur = cur->next)
+	      LineDefs[cur->objnum].sidedef1 = val;
+	    MadeChanges = 1;
+	    MadeMapChanges = 1;
+	  }
+	  break;
+
+	case 7:
+	  val = InputObjectXRef (x0 + 84, subsubwin_y0,
+	    OBJ_SIDEDEFS, 1, LineDefs[obj->objnum].sidedef2);
+	  if (val >= -1)
+	  {
+	    for (cur = obj; cur; cur = cur->next)
+	      LineDefs[cur->objnum].sidedef2 = val;
+	    MadeChanges = 1;
+	    MadeMapChanges = 1;
+	  }
+	  break;
+     }
+     break;
+
+    // Edit or add the first sidedef
+    case 2:
+      ObjectsNeeded (OBJ_LINEDEFS, OBJ_SIDEDEFS, 0);
+      if (LineDefs[obj->objnum].sidedef1 >= 0)
+      {
+	// Build a new selection list with the first sidedefs
+	objtype = OBJ_SIDEDEFS;
+	sdlist = 0;
+	for (cur = obj; cur; cur = cur->next)
+	  if (LineDefs[cur->objnum].sidedef1 >= 0)
+	    SelectObject (&sdlist, LineDefs[cur->objnum].sidedef1);
+      }
+      else
+      {
+	// Add a new first sidedef
+	for (cur = obj; cur; cur = cur->next)
+	  if (LineDefs[cur->objnum].sidedef1 == -1)
+	  {
+	    InsertObject (OBJ_SIDEDEFS, -1, 0, 0);
+	    LineDefs[cur->objnum].sidedef1 = NumSideDefs - 1;
+	  }
+	break;
+      }
+      // FALL THROUGH
+
+    // Edit or add the second sidedef
+    case 3:
+      if (objtype != OBJ_SIDEDEFS)
+      {
+	if (LineDefs[obj->objnum].sidedef2 >= 0)
+	{
+	  // Build a new selection list with the second (or first) SideDefs
+	  objtype = OBJ_SIDEDEFS;
+	  sdlist = 0;
+	  for (cur = obj; cur; cur = cur->next)
+	    if (LineDefs[cur->objnum].sidedef2 >= 0)
+	      SelectObject (&sdlist, LineDefs[cur->objnum].sidedef2);
+	    else if (LineDefs[cur->objnum].sidedef1 >= 0)
+	      SelectObject (&sdlist, LineDefs[cur->objnum].sidedef1);
+	}
+	else
+	{
+	  // Add a new second (or first) sidedef
+	  for (cur = obj; cur; cur = cur->next)
+	    if (LineDefs[cur->objnum].sidedef1 == -1)
+	    {
+	      InsertObject (OBJ_SIDEDEFS, -1, 0, 0);
+	      ObjectsNeeded (OBJ_LINEDEFS, 0);
+	      LineDefs[cur->objnum].sidedef1 = NumSideDefs - 1;
+	    }
+	    else if (LineDefs[cur->objnum].sidedef2 == -1)
+	    {
+	      n = LineDefs[cur->objnum].sidedef1;
+	      InsertObject (OBJ_SIDEDEFS, -1, 0, 0);
+	      strncpy (SideDefs[NumSideDefs - 1].tex3, "-", WAD_TEX_NAME);
+	      strncpy (SideDefs[n].tex3, "-", WAD_TEX_NAME);
+	      ObjectsNeeded (OBJ_LINEDEFS, 0);
+	      LineDefs[cur->objnum].sidedef2 = NumSideDefs - 1;
+	      LineDefs[cur->objnum].flags ^= 4;  // Set the 2S bit
+	      LineDefs[cur->objnum].flags &= ~1;  // Clear the Im bit
+	    }
+	  break;
+	}
+      }
+      ObjectsNeeded (OBJ_SIDEDEFS, 0);
+      for (n = 0; n < 7; n++)
+	menustr[n] = (char *) GetMemory (60);
+      sprintf (menustr[6], "Edit sidedef #%d", sdlist->objnum);
+      texname[WAD_TEX_NAME] = '\0';
+      strncpy (texname, SideDefs[sdlist->objnum].tex3, WAD_TEX_NAME);
+      sprintf (menustr[0], "Change middle texture   (Current: %s)", texname);
+      strncpy (texname, SideDefs[sdlist->objnum].tex1, WAD_TEX_NAME);
+      sprintf (menustr[1], "Change upper texture    (Current: %s)", texname);
+      strncpy (texname, SideDefs[sdlist->objnum].tex2, WAD_TEX_NAME);
+      sprintf (menustr[2], "Change lower texture    (Current: %s)", texname);
+      sprintf (menustr[3], "Change texture X offset (Current: %d)",
+	SideDefs[sdlist->objnum].xoff);
+      sprintf (menustr[4], "Change texture Y offset (Current: %d)",
+	SideDefs[sdlist->objnum].yoff);
+      sprintf (menustr[5], "Change sector ref.      (Current: #%d)",
+	SideDefs[sdlist->objnum].sector);
+      val = vDisplayMenu (x0 + 42, subwin_y0, menustr[6],
+	menustr[0], YK_, 0,
+	menustr[1], YK_, 0,
+	menustr[2], YK_, 0,
+	menustr[3], YK_, 0,
+	menustr[4], YK_, 0,
+	menustr[5], YK_, 0,
+	NULL);
+      for (n = 0; n < 7; n++)
+	FreeMemory (menustr[n]);
+      subsubwin_y0 = subwin_y0 + BOX_BORDER + (2 + val) * FONTH;
+      switch (val)
+      {
+	case 1:
+	  strncpy (texname, SideDefs[sdlist->objnum].tex3, WAD_TEX_NAME);
+	  ObjectsNeeded (0);
+	  ChooseWallTexture (x0 + 84, subsubwin_y0 ,
+	    "Choose a wall texture", NumWTexture, WTexture, texname);
+	  ObjectsNeeded (OBJ_SIDEDEFS, 0);
+	  if (strlen (texname) > 0)
+	  {
+	    for (cur = sdlist; cur; cur = cur->next)
+	      if (cur->objnum >= 0)
+		strncpy (SideDefs[cur->objnum].tex3, texname, WAD_TEX_NAME);
+	    MadeChanges = 1;
+	  }
+	  break;
+
+	case 2:
+	  strncpy (texname, SideDefs[sdlist->objnum].tex1, WAD_TEX_NAME);
+	  ObjectsNeeded (0);
+	  ChooseWallTexture (x0 + 84, subsubwin_y0,
+	     "Choose a wall texture", NumWTexture, WTexture, texname);
+	  ObjectsNeeded (OBJ_SIDEDEFS, 0);
+	  if (strlen (texname) > 0)
+	  {
+	    for (cur = sdlist; cur; cur = cur->next)
+	      if (cur->objnum >= 0)
+		strncpy (SideDefs[cur->objnum].tex1, texname, WAD_TEX_NAME);
+	    MadeChanges = 1;
+	  }
+	  break;
+
+	case 3:
+	  strncpy (texname, SideDefs[sdlist->objnum].tex2, WAD_TEX_NAME);
+	  ObjectsNeeded (0);
+	  ChooseWallTexture (x0 + 84, subsubwin_y0,
+	    "Choose a wall texture", NumWTexture, WTexture, texname);
+	  ObjectsNeeded (OBJ_SIDEDEFS, 0);
+	  if (strlen (texname) > 0)
+	  {
+	    for (cur = sdlist; cur; cur = cur->next)
+	      if (cur->objnum >= 0)
+		strncpy (SideDefs[cur->objnum].tex2, texname, WAD_TEX_NAME);
+	    MadeChanges = 1;
+	  }
+	  break;
+
+	case 4:
+	  val = InputIntegerValue (x0 + 84, subsubwin_y0,
+	    -32768, 32767, SideDefs[sdlist->objnum].xoff);
+	  if (val != IIV_CANCEL)
+	  {
+	    for (cur = sdlist; cur; cur = cur->next)
+	      if (cur->objnum >= 0)
+		SideDefs[cur->objnum].xoff = val;
+	    MadeChanges = 1;
+	  }
+	  break;
+
+	case 5:
+	  val = InputIntegerValue (x0 + 84, subsubwin_y0,
+	    -32768, 32767, SideDefs[sdlist->objnum].yoff);
+	  if (val != IIV_CANCEL)
+	  {
+	    for (cur = sdlist; cur; cur = cur->next)
+	      if (cur->objnum >= 0)
+		SideDefs[cur->objnum].yoff = val;
+	    MadeChanges = 1;
+	  }
+	  break;
+
+	case 6:
+	  val = InputObjectXRef (x0 + 84, subsubwin_y0,
+	    OBJ_SECTORS, 0, SideDefs[sdlist->objnum].sector);
+	  if (val >= 0)
+	  {
+	    for (cur = sdlist; cur; cur = cur->next)
+	      if (cur->objnum >= 0)
+		SideDefs[cur->objnum].sector = val;
+	    MadeChanges = 1;
+	  }
+	  break;
+      }
+      ForgetSelection (&sdlist);
+      break;
+  }
+}
+
+
+/*
+*/
+
+static char *GetTaggedLineDefFlag (int linedefnum, int flagndx)
+{
+  static char ldstr[16][50];
+
+  if ((LineDefs[linedefnum].flags & (0x01 << (flagndx - 1))) != 0)
+    strcpy (ldstr[flagndx - 1], "* ");
+  else
+    strcpy (ldstr[flagndx - 1], "  ");
+  strcat (ldstr[flagndx - 1], GetLineDefFlagsLongName (0x01 << (flagndx - 1)));
+  return ldstr[flagndx - 1];
+}
+
+
+
+/*
+ *	InputLinedefType
+ *	Let the user select a linedef type number and return it.
+ *	Returns 0 if OK, <>0 if cancelled
+ */
+static int InputLinedefType (int x0, int y0, int *number)
+{
+  int         r;
+  int         ldtgno = 0;
+  char        ldtg; 
+  al_llist_t *list = 0;
+
+  for (;;)
+  {
+    /* First let user select a ldtgroup */
+    if (DisplayMenuList (x0+84, y0, "Select group", ldtgroup,
+     PrintLdtgroup, &ldtgno) < 0)
+      return 1;
+    if (al_lseek (ldtgroup, ldtgno, SEEK_SET))
+      fatal_error ("%s ILT1 (%s)", msg_unexpected, al_astrerror (al_aerrno));
+    ldtg = CUR_LDTGROUP->ldtgroup;
+
+    /* KLUDGE: Special ldtgroup LDT_FREE means "enter number"
+       Don't look for this ldtgroup in the .ygd file :
+       LoadGameDefs() creates it manually. */
+    if (ldtg == LDT_FREE)
+    {
+      // FIXME should be unsigned
+      *number = InputIntegerValue (x0+126, y0 + (3 + ldtgno) * FONTH,
+	 -32768, 32767, 0);
+      if (*number != IIV_CANCEL)
+	break;
+      goto again;
+    }
+      
+    /* Then build a list of pointers on all ldt that have this
+       ldtgroup and let user select one */
+    list = al_lcreate (sizeof (void *));
+    for (al_lrewind (ldtdef); ! al_leol (ldtdef); al_lstep (ldtdef))
+      if (CUR_LDTDEF->ldtgroup == ldtg)
+      {
+	void *ptr = CUR_LDTDEF;
+	al_lwrite (list, &ptr);
+      }
+    {
+      Menu_data_ldt menudata (list);
+      r = DisplayMenuList
+       (x0+126, y0 + 2 * FONTH, "Select type", menudata, NULL);
+    }
+    if (r < 0)
+      goto again;
+    if (al_lseek (list, r, SEEK_SET))
+      fatal_error ("%s ILT2 (%s)", msg_unexpected, al_astrerror (al_aerrno));
+    *number = (*((ldtdef_t **) al_lptr (list)))->number;
+    al_ldiscard (list);
+    break;
+
+    again :
+    ;
+    /* draw_map (OBJ_THINGS, 0, 0);  FIXME! */
+  }
+
+  return 0;
+}
+
+
+/*
+ *	PrintLdtgroup
+ *	Used by DisplayMenuList when called by InputLinedefType
+ */
+static const char *PrintLdtgroup (void *ptr)
+{
+  if (! ptr)
+    return "PrintLdtgroup: (null)";
+  return ((ldtgroup_t *)ptr)->desc;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/l_super.h	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,148 @@
+/*
+ *	l_super.h - Superimposed_ld class
+ *	AYM 2003-12-02
+ */
+
+/*
+This file is copyright André Majorel 2003.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of version 2 of the GNU General Public License as published by the
+Free Software Foundation.
+
+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.
+*/
+
+
+#ifndef YH_L_SUPER  /* DO NOT INSERT ANYTHING BEFORE THIS LINE */
+#define YH_L_SUPER
+
+#include "levels.h"
+#include "objid.h"
+
+
+/* The Superimposed_ld class is used to find all the linedefs that are
+   superimposed with a particular reference linedef. Call the set()
+   method to specify the reference linedef. Each call to the get()
+   method returns the number of the next superimposed linedef, or -1
+   when there are no more superimposed linedefs.
+
+   Two linedefs are superimposed iff their ends have the same map
+   coordinates, regardless of whether the vertex numbers are the same,
+   and irrespective of start/end vertex distinctions. */
+
+class Superimposed_ld
+{
+  public:
+             Superimposed_ld ();
+    int      set             (obj_no_t);
+    obj_no_t get             ();
+    void     rewind          ();
+
+  private:
+    obj_no_t refldno;			// Reference linedef
+    obj_no_t ldno;			// get() will start from there
+};
+
+
+inline Superimposed_ld::Superimposed_ld ()
+{
+  refldno = -1;
+  rewind ();
+}
+
+
+/*
+ *	Superimposed_ld::set - set the reference linedef
+ *
+ *	If the argument is not a valid linedef number, does nothing and
+ *	returns a non-zero value. Otherwise, set the linedef number,
+ *	calls rewind() and returns a zero value.
+ */
+inline int Superimposed_ld::set (obj_no_t ldno)
+{
+  if (! is_linedef (ldno))		// Paranoia
+    return 1;
+
+  refldno = ldno;
+  rewind ();
+  return 0;
+}
+
+
+/*
+ *	Superimposed_ld::get - return the next superimposed linedef
+ *
+ *	Returns the number of the next superimposed linedef, or -1 if
+ *	there's none. If the reference linedef was not specified, or is
+ *	invalid (possibly as a result of changes in the level), returns
+ *	-1.
+ *
+ *	Linedefs that have invalid start/end vertices are silently
+ *	skipped.
+ */
+inline obj_no_t Superimposed_ld::get ()
+{
+  if (refldno == -1)
+    return -1;
+
+  /* These variables are there to speed things up a bit by avoiding
+     repetitive table lookups. Everything is re-computed each time as
+     LineDefs could very well be realloc'd while we were out. */
+
+  if (! is_linedef (refldno))
+    return -1;
+  const struct LineDef *const pmax = LineDefs + NumLineDefs;
+  const struct LineDef *const pref = LineDefs + refldno;
+
+  const wad_vn_t refv0 = pref->start;
+  const wad_vn_t refv1 = pref->end;
+  if (! is_vertex (refv0) || ! is_vertex (refv1))		// Paranoia
+    return -1;
+
+  const wad_coord_t refx0 = Vertices[refv0].x;
+  const wad_coord_t refy0 = Vertices[refv0].y;
+  const wad_coord_t refx1 = Vertices[refv1].x;
+  const wad_coord_t refy1 = Vertices[refv1].y;
+
+  for (const struct LineDef *p = LineDefs + ldno; ldno < NumLineDefs;
+      p++, ldno++)
+  {
+    if (! is_vertex (p->start) || ! is_vertex (p->end))		// Paranoia
+      continue;
+    obj_no_t x0 = Vertices[p->start].x;
+    obj_no_t y0 = Vertices[p->start].y;
+    obj_no_t x1 = Vertices[p->end].x;
+    obj_no_t y1 = Vertices[p->end].y;
+    if ( x0 == refx0 && y0 == refy0 && x1 == refx1 && y1 == refy1
+      || x0 == refx1 && y0 == refy1 && x1 == refx0 && y1 == refy0)
+    {
+      if (ldno == refldno)
+	continue;
+      return ldno++;
+    }
+  }
+
+  return -1;
+}
+
+
+/*
+ *	Superimposed_ld::rewind - rewind the counter
+ *
+ *	After calling this method, the next call to get() will start
+ *	from the first linedef.
+ */
+inline void Superimposed_ld::rewind ()
+{
+  ldno = 0;
+}
+
+
+#endif  /* DO NOT ADD ANYTHING AFTER THIS LINE */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/l_unlink.cc	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,112 @@
+/*
+ *	l_unlink.cc
+ *	AYM 1998-11-07
+ */
+
+
+/*
+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 "bitvec.h"
+#include "levels.h"
+#include "objects.h"
+#include "objid.h"
+#include "selectn.h"
+
+
+/*
+ *	unlink_sidedef
+ *
+ *	For all linedefs in the <linedefs>, see whether the sidedefs
+ *	are used by any other linedef _not_in_<linedefs>_. If they
+ *	are, duplicate the sidedefs and assign the new duplicate to
+ *	the linedef.
+ *	If <side1> is set, take care of the first sidedef.
+ *	If <side2> is set, take care of the second sidedef.
+ *	Both can be set, of course.
+ *
+ *	This function is intended to "unlink" duplicated linedefs.
+ */
+void unlink_sidedef (SelPtr linedefs, int side1, int side2)
+{
+// Array of NumSideDefs bits that tell whether the
+// sidedef is used by the linedefs in <linedefs>.
+bitvec_c sd_used_in (NumSideDefs);
+
+// Array of NumSideDefs bits that tell whether the
+// sidedef is used by the linedefs _not_ in <linedefs>.
+bitvec_c sd_used_out (NumSideDefs);
+
+SelPtr cur;
+int n;
+
+ObjectsNeeded (OBJ_LINEDEFS, OBJ_SIDEDEFS, 0);
+
+// Put in sd_used_in a list of all sidedefs
+// that are used by linedefs in <linedefs>.
+// and in sd_used_out a list of all sidedefs
+// that are used by linedefs not in <linedefs>
+
+for (n = 0; n < NumLineDefs; n++)
+   {
+   if (IsSelected (linedefs, n))
+      {
+      if (side1 && is_sidedef (LineDefs[n].sidedef1))
+         sd_used_in.set (LineDefs[n].sidedef1);
+      if (side2 && is_sidedef (LineDefs[n].sidedef2))
+         sd_used_in.set (LineDefs[n].sidedef2);
+      }
+   else
+      {
+      if (is_sidedef (LineDefs[n].sidedef1))
+	 sd_used_out.set (LineDefs[n].sidedef1);
+      if (is_sidedef (LineDefs[n].sidedef2))
+	 sd_used_out.set (LineDefs[n].sidedef2);
+      }
+   }
+
+// For all sidedefs that are used both by a linedef
+// in <linedefs> and a linedef _not_ in <linedefs>,
+// duplicate the sidedef and make all the linedefs
+// in <linedefs> use the copy instead.
+
+for (n = 0; n < NumSideDefs; n++)
+   {
+   if (sd_used_in.get (n) && sd_used_out.get (n))
+      {
+      InsertObject (OBJ_SIDEDEFS, n, 0, 0);
+      for (cur = linedefs; cur; cur = cur->next)
+         {
+         if (side1 && LineDefs[cur->objnum].sidedef1 == n)
+            LineDefs[cur->objnum].sidedef1 = NumSideDefs - 1;
+         if (side2 && LineDefs[cur->objnum].sidedef2 == n)
+            LineDefs[cur->objnum].sidedef2 = NumSideDefs - 1;
+         }
+      }
+   }
+}
+
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/l_vertices.cc	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,98 @@
+/*
+ *	l_vertices.cc
+ *	AYM 1998-11-22
+ */
+
+
+/*
+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 "bitvec.h"
+#include "l_vertices.h"
+#include "levels.h"
+
+
+/*
+ *	bv_vertices_of_linedefs
+ *	Return a bit vector of all vertices used by the linedefs.
+ *	It's up to the caller to delete the bit vector after use.
+ */
+bitvec_c *bv_vertices_of_linedefs (bitvec_c *linedefs)
+{
+bitvec_c *vertices;
+int n;
+
+vertices = new bitvec_c (NumVertices);
+for (n = 0; n < NumLineDefs; n++)
+   if (linedefs->get (n))
+      {
+      vertices->set (LineDefs[n].start);
+      vertices->set (LineDefs[n].end);
+      }
+return vertices;
+}
+
+
+/*
+ *	bv_vertices_of_linedefs
+ *	Return a bit vector of all vertices used by the linedefs.
+ *	It's up to the caller to delete the bit vector after use.
+ */
+bitvec_c *bv_vertices_of_linedefs (SelPtr list)
+{
+bitvec_c *vertices;
+SelPtr cur;
+
+vertices = new bitvec_c (NumVertices);
+for (cur = list; cur; cur = cur->next)
+   {
+   vertices->set (LineDefs[cur->objnum].start);
+   vertices->set (LineDefs[cur->objnum].end);
+   }
+return vertices;
+}
+
+
+/*
+ *	list_vertices_of_linedefs
+ *	Return a list of all vertices used by the linedefs
+ *	It's up to the caller to delete the list after use.
+ */
+SelPtr list_vertices_of_linedefs (SelPtr list)
+{
+bitvec_c *vertices_bitvec;
+SelPtr vertices_list = 0;
+size_t n;
+
+vertices_bitvec = bv_vertices_of_linedefs (list);
+for (n = 0; n < vertices_bitvec->nelements (); n++)
+   {
+   if (vertices_bitvec->get (n))
+      SelectObject (&vertices_list, n);
+   }
+delete vertices_bitvec;
+return vertices_list;
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/l_vertices.h	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,14 @@
+/*
+ *	l_vertices.h
+ *	AYM 1998-11-22
+ */
+
+
+class bitvec_c;
+#include "selectn.h"
+
+
+bitvec_c *bv_vertices_of_linedefs (bitvec_c *linedefs);
+bitvec_c *bv_vertices_of_linedefs (SelPtr list);
+SelPtr list_vertices_of_linedefs (SelPtr list);
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/levels.cc	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,1709 @@
+/*
+ *	levels.cc
+ *	Level loading and saving routines,
+ *	global variables used to hold the level data.
+ *	BW & RQ sometime in 1993 or 1994.
+ */
+
+
+/*
+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 "bitvec.h"
+#include "dialog.h"
+#include "game.h"
+#include "levels.h"
+#include "objid.h"
+#include "wstructs.h"
+#include "things.h"
+#include "wadfile.h"
+#include "wads.h"
+#include "wads2.h"
+
+
+/*
+ 	FIXME
+	All these variables should be turned
+	into members of a "Level" class.
+*/
+MDirPtr Level;			/* master dictionary entry for the level */
+int NumThings;			/* number of things */
+TPtr Things;			/* things data */
+int NumLineDefs;		/* number of line defs */
+LDPtr LineDefs;			/* line defs data */
+int NumSideDefs;		/* number of side defs */
+SDPtr SideDefs;			/* side defs data */
+int NumVertices;		/* number of vertexes */
+VPtr Vertices;			/* vertex data */
+int NumSectors;			/* number of sectors */
+SPtr Sectors;			/* sectors data */
+
+// FIXME should be somewhere else
+int NumWTexture;		/* number of wall textures */
+char **WTexture;		/* array of wall texture names */
+
+// FIXME all the flat list stuff should be put in a separate class
+size_t NumFTexture;		/* number of floor/ceiling textures */
+flat_list_entry_t *flat_list;	// List of all flats in the directory
+
+int MapMaxX = -32767;		/* maximum X value of map */
+int MapMaxY = -32767;		/* maximum Y value of map */
+int MapMinX = 32767;		/* minimum X value of map */
+int MapMinY = 32767;		/* minimum Y value of map */
+bool MadeChanges;		/* made changes? */
+bool MadeMapChanges;		/* made changes that need rebuilding? */
+unsigned long things_angles;	// See levels.h for description.
+unsigned long things_types;	// See levels.h for description.
+char Level_name[WAD_NAME + 1];	/* The name of the level (E.G.
+				   "MAP01" or "E1M1"), followed by a
+				   NUL. If the Level has been created as
+				   the result of a "c" command with no
+				   argument, an empty string. The name
+				   is not necesarily in upper case but
+				   it always a valid lump name, not a
+				   command line shortcut like "17". */
+
+y_file_name_t Level_file_name;	/* The name of the file in which
+				   the level would be saved. If the
+				   level has been created as the result
+				   of a "c" command, with or without
+				   argument, an empty string. */
+
+y_file_name_t Level_file_name_saved;  /* The name of the file in
+				   which the level was last saved. If
+				   the Level has never been saved yet,
+				   an empty string. */
+
+void EmptyLevelData (const char *levelname)
+{
+Things = 0;
+NumThings = 0;
+things_angles++;
+things_types++;
+LineDefs = 0;
+NumLineDefs = 0;
+SideDefs = 0;
+NumSideDefs = 0;
+Sectors = 0;
+NumSectors = 0;
+Vertices = 0;
+NumVertices = 0;
+}
+
+
+/*
+ *	texno_texname
+ *	A convenience function when loading Doom alpha levels
+ */
+static char *tex_list = 0;
+static size_t ntex = 0;
+static char tex_name[WAD_TEX_NAME + 1];
+inline const char *texno_texname (i16 texno)
+{
+if (texno < 0)
+   return "-";
+else
+   if (yg_texture_format == YGTF_NAMELESS)
+      {
+      sprintf (tex_name, "TEX%04u", (unsigned) texno);
+      return tex_name;
+      }
+   else
+      {
+      if (texno < (i16) ntex)
+	 return tex_list + WAD_TEX_NAME * texno;
+      else
+	 return "unknown";
+      }
+}
+
+
+/*
+   read in the level data
+*/
+
+int ReadLevelData (const char *levelname) /* SWAP! */
+{
+int rc = 0;
+MDirPtr dir;
+int OldNumVertices;
+
+/* No objects are needed: they may be swapped after they have been read */
+ObjectsNeeded (0);
+
+/* Find the various level information from the master directory */
+DisplayMessage (-1, -1, "Reading data for level %s...", levelname);
+Level = FindMasterDir (MasterDir, levelname);
+if (!Level)
+   fatal_error ("level data not found");
+
+/* Get the number of vertices */
+i32 v_offset = 42;
+i32 v_length = 42;
+{
+const char *lump_name = "BUG";
+if (yg_level_format == YGLF_ALPHA)  // Doom alpha
+   lump_name = "POINTS";
+else
+   lump_name = "VERTEXES";
+dir = FindMasterDir (Level, lump_name);
+if (dir == 0)
+   OldNumVertices = 0;
+else
+   {
+   v_offset = dir->dir.start;
+   v_length = dir->dir.size;
+   if (yg_level_format == YGLF_ALPHA)  // Doom alpha: skip leading count
+      {
+      v_offset += 4;
+      v_length -= 4;
+      }
+   OldNumVertices = (int) (v_length / WAD_VERTEX_BYTES);
+   if ((i32) (OldNumVertices * WAD_VERTEX_BYTES) != v_length)
+      warn ("the %s lump has a weird size."
+        " The wad might be corrupt.\n", lump_name);
+   }
+}
+
+// Read THINGS
+{
+const char *lump_name = "THINGS";
+verbmsg ("Reading %s things", levelname);
+i32 offset = 42;
+i32 length;
+dir = FindMasterDir (Level, lump_name);
+if (dir == 0)
+   NumThings = 0;
+else
+   {
+   offset = dir->dir.start;
+   length = dir->dir.size;
+   if (MainWad == Iwad4)  // Hexen mode
+      {
+      NumThings = (int) (length / WAD_HEXEN_THING_BYTES);
+      if ((i32) (NumThings * WAD_HEXEN_THING_BYTES) != length)
+         warn ("the %s lump has a weird size."
+            " The wad might be corrupt.\n", lump_name);
+      }
+   else                    // Doom/Heretic/Strife mode
+      {
+      if (yg_level_format == YGLF_ALPHA)  // Doom alpha: skip leading count
+	 {
+	 offset += 4;
+	 length -= 4;
+	 }
+      size_t thing_size = yg_level_format == YGLF_ALPHA ? 12 : WAD_THING_BYTES;
+      NumThings = (int) (length / thing_size);
+      if ((i32) (NumThings * thing_size) != length)
+         warn ("the %s lump has a weird size."
+            " The wad might be corrupt.\n", lump_name);
+      }
+   }
+things_angles++;
+things_types++;
+if (NumThings > 0)
+   {
+   Things = (TPtr) GetFarMemory ((unsigned long) NumThings
+      * sizeof (struct Thing));
+   const Wad_file *wf = dir->wadfile;
+   wf->seek (offset);
+   if (wf->error ())
+      {
+      err ("%s: seek error", lump_name);
+      rc = 1;
+      goto byebye;
+      }
+   if (MainWad == Iwad4)		// Hexen mode
+      for (long n = 0; n < NumThings; n++)
+	 {
+         u8 dummy2[6];
+	 wf->read_i16   ();					// Tid
+	 wf->read_i16   (&Things[n].xpos );
+	 wf->read_i16   (&Things[n].ypos );
+	 wf->read_i16   ();					// Height
+	 wf->read_i16   (&Things[n].angle);
+	 wf->read_i16   (&Things[n].type );
+	 wf->read_i16   (&Things[n].when );
+         wf->read_bytes (dummy2, sizeof dummy2);
+	 if (wf->error ())
+	    {
+	    err ("%s: error reading thing #%ld", lump_name, n);
+	    rc = 1;
+	    goto byebye;
+	    }
+	 }
+   else					// Doom/Heretic/Strife mode
+      for (long n = 0; n < NumThings; n++)
+	 {
+	 wf->read_i16 (&Things[n].xpos );
+	 wf->read_i16 (&Things[n].ypos );
+	 wf->read_i16 (&Things[n].angle);
+	 wf->read_i16 (&Things[n].type );
+	 if (yg_level_format == YGLF_ALPHA)
+	    wf->read_i16 ();		// Alpha. Don't know what it's for.
+	 wf->read_i16 (&Things[n].when );
+	 if (wf->error ())
+	    {
+	    err ("%s: error reading thing #%ld", lump_name, n);
+	    rc = 1;
+	    goto byebye;
+	    }
+	 }
+   }
+}
+
+// Read LINEDEFS
+if (yg_level_format != YGLF_ALPHA)
+   {
+   const char *lump_name = "LINEDEFS";
+   verbmsg (" linedefs");
+   dir = FindMasterDir (Level, lump_name);
+   if (dir == 0)
+      NumLineDefs = 0;
+   else
+      {
+      if (MainWad == Iwad4)  // Hexen mode
+	 {
+	 NumLineDefs = (int) (dir->dir.size / WAD_HEXEN_LINEDEF_BYTES);
+	 if ((i32) (NumLineDefs * WAD_HEXEN_LINEDEF_BYTES) != dir->dir.size)
+	    warn ("the %s lump has a weird size."
+	       " The wad might be corrupt.\n", lump_name);
+	 }
+      else                   // Doom/Heretic/Strife mode
+	 {
+	 NumLineDefs = (int) (dir->dir.size / WAD_LINEDEF_BYTES);
+	 if ((i32) (NumLineDefs * WAD_LINEDEF_BYTES) != dir->dir.size)
+	    warn ("the %s lump has a weird size."
+	       " The wad might be corrupt.\n", lump_name);
+	 }
+      }
+   if (NumLineDefs > 0)
+      {
+      LineDefs = (LDPtr) GetFarMemory ((unsigned long) NumLineDefs
+	 * sizeof (struct LineDef));
+      const Wad_file *wf = dir->wadfile;
+      wf->seek (dir->dir.start);
+      if (wf->error ())
+	 {
+	 err ("%s: seek error", lump_name);
+	 rc = 1;
+	 goto byebye;
+	 }
+      if (MainWad == Iwad4)  // Hexen mode
+	 for (long n = 0; n < NumLineDefs; n++)
+	    {
+	    u8 dummy[6];
+	    wf->read_i16   (&LineDefs[n].start);
+	    wf->read_i16   (&LineDefs[n].end);
+	    wf->read_i16   (&LineDefs[n].flags);
+	    wf->read_bytes (dummy, sizeof dummy);
+	    wf->read_i16   (&LineDefs[n].sidedef1);
+	    wf->read_i16   (&LineDefs[n].sidedef2);
+	    LineDefs[n].type = dummy[0];
+	    LineDefs[n].tag  = dummy[1];  // arg1 often contains a tag
+	    if (wf->error ())
+	       {
+	       err ("%s: error reading linedef #%ld", lump_name, n);
+	       rc = 1;
+	       goto byebye;
+	       }
+	    }
+      else                   // Doom/Heretic/Strife mode
+	 for (long n = 0; n < NumLineDefs; n++)
+	    {
+	    wf->read_i16 (&LineDefs[n].start);
+	    wf->read_i16 (&LineDefs[n].end);
+	    wf->read_i16 (&LineDefs[n].flags);
+	    wf->read_i16 (&LineDefs[n].type);
+	    wf->read_i16 (&LineDefs[n].tag);
+	    wf->read_i16 (&LineDefs[n].sidedef1);
+	    wf->read_i16 (&LineDefs[n].sidedef2);
+	    if (wf->error ())
+	       {
+	       err ("%s: error reading linedef #%ld", lump_name, n);
+	       rc = 1;
+	       goto byebye;
+	       }
+	    }
+      }
+   }
+
+// Read SIDEDEFS
+{
+const char *lump_name = "SIDEDEFS";
+verbmsg (" sidedefs");
+dir = FindMasterDir (Level, lump_name);
+if (dir)
+   {
+   NumSideDefs = (int) (dir->dir.size / WAD_SIDEDEF_BYTES);
+   if ((i32) (NumSideDefs * WAD_SIDEDEF_BYTES) != dir->dir.size)
+      warn ("the SIDEDEFS lump has a weird size."
+         " The wad might be corrupt.\n");
+   }
+else
+   NumSideDefs = 0;
+if (NumSideDefs > 0)
+   {
+   SideDefs = (SDPtr) GetFarMemory ((unsigned long) NumSideDefs
+      * sizeof (struct SideDef));
+   const Wad_file *wf = dir->wadfile;
+   wf->seek (dir->dir.start);
+   if (wf->error ())
+      {
+      err ("%s: seek error", lump_name);
+      rc = 1;
+      goto byebye;
+      }
+   for (long n = 0; n < NumSideDefs; n++)
+      {
+      wf->read_i16   (&SideDefs[n].xoff);
+      wf->read_i16   (&SideDefs[n].yoff);
+      wf->read_bytes (&SideDefs[n].tex1, WAD_TEX_NAME);
+      wf->read_bytes (&SideDefs[n].tex2, WAD_TEX_NAME);
+      wf->read_bytes (&SideDefs[n].tex3, WAD_TEX_NAME);
+      wf->read_i16   (&SideDefs[n].sector);
+      if (wf->error ())
+	 {
+	 err ("%s: error reading sidedef #%ld", lump_name, n);
+	 rc = 1;
+	 goto byebye;
+	 }
+      }
+   }
+}
+
+/* Sanity checkings on linedefs: the 1st and 2nd vertices
+   must exist. The 1st and 2nd sidedefs must exist or be
+   set to -1. */
+for (long n = 0; n < NumLineDefs; n++)
+   {
+   if (LineDefs[n].sidedef1 != -1
+      && outside (LineDefs[n].sidedef1, 0, NumSideDefs - 1))
+      {
+      err ("linedef %ld has bad 1st sidedef number %d, giving up",
+	 n, LineDefs[n].sidedef1);
+      rc = 1;
+      goto byebye;
+      }
+   if (LineDefs[n].sidedef2 != -1
+      && outside (LineDefs[n].sidedef2, 0, NumSideDefs - 1))
+      {
+      err ("linedef %ld has bad 2nd sidedef number %d, giving up",
+	 n, LineDefs[n].sidedef2);
+      rc = 1;
+      goto byebye;
+      }
+   if (outside (LineDefs[n].start, 0, OldNumVertices -1))
+      {
+      err ("linedef %ld has bad 1st vertex number %d, giving up",
+        n, LineDefs[n].start);
+      rc = 1;
+      goto byebye;
+      }
+   if (outside (LineDefs[n].end, 0, OldNumVertices - 1))
+      {
+      err ("linedef %ld has bad 2nd vertex number %d, giving up",
+        n, LineDefs[n].end);
+      rc = 1;
+      goto byebye;
+      }
+   }
+
+// Read LINES (Doom alpha only)
+if (yg_level_format == YGLF_ALPHA)
+   {
+   const char *lump_name = "LINES";
+   verbmsg (" lines");
+   dir = FindMasterDir (Level, lump_name);
+   if (dir)
+      {
+      if ((dir->dir.size - 4) % 36)
+	 warn ("the %s lump has a weird size. The wad might be corrupt.\n",
+	    lump_name);
+      const size_t nlines = dir->dir.size / 36;
+      NumLineDefs = nlines;
+      NumSideDefs = 2 * nlines;  // Worst case. We'll adjust later.
+      LineDefs = (LDPtr) GetFarMemory ((unsigned long) NumLineDefs
+	 * sizeof (struct LineDef));
+      SideDefs = (SDPtr) GetFarMemory ((unsigned long) NumSideDefs
+	 * sizeof (struct SideDef));
+      // Read TEXTURES
+      if (yg_texture_format != YGTF_NAMELESS)
+	 {
+	 const char *lump_name = "TEXTURES";
+	 bool success = false;
+	 ntex = 0;
+	 i32 *offset_table = 0;
+	 MDirPtr d = FindMasterDir (MasterDir, lump_name);
+	 if (! d)
+	    {
+	    warn ("%s: lump not found in directory\n", lump_name);
+	    goto textures_done;
+	    }
+	 {
+	 const Wad_file *wf = d->wadfile;
+	 wf->seek (d->dir.start);
+	 if (wf->error ())
+	    {
+	    warn ("%s: seek error\n", lump_name);
+	    goto textures_done;
+	    }
+	 i32 num;
+	 wf->read_i32 (&num);
+	 if (wf->error ())
+	    {
+	    warn ("%s: error reading texture count\n", lump_name);
+	    }
+	 if (num < 0 || num > 32767)
+	    {
+	    warn ("%s: bad texture count, giving up\n", lump_name);
+	    goto textures_done;
+	    }
+	 ntex = num;
+	 offset_table = new i32[ntex];
+	 for (size_t n = 0; n < ntex; n++)
+	    {
+	    wf->read_i32 (offset_table + n);
+	    if (wf->error ())
+	       {
+	       warn ("%s: error reading offsets table\n");
+	       goto textures_done;
+	       }
+	    }
+	 tex_list = (char *) GetMemory (ntex * WAD_TEX_NAME);
+	 for (size_t n = 0; n < ntex; n++)
+	    {
+	    const long offset = d->dir.start + offset_table[n];
+	    wf->seek (offset);
+	    if (wf->error ())
+	       {
+	       warn ("%s: seek error\n", lump_name);
+	       goto textures_done;
+	       }
+	    wf->read_bytes (tex_list + WAD_TEX_NAME * n, WAD_TEX_NAME);
+	    if (wf->error ())
+	       {
+	       warn ("%s: error reading texture names\n", lump_name);
+	       goto textures_done;
+	       }
+	    }
+	 success = true;
+	 }
+
+	 textures_done:
+	 if (offset_table != 0)
+	    delete[] offset_table;
+	 if (! success)
+	    warn ("%s: errors found, won't be able to import texture names\n",
+	       lump_name);
+	 }
+
+      const Wad_file *wf = dir->wadfile;
+      wf->seek (dir->dir.start + 4);
+      if (wf->error ())
+	 {
+	 err ("%s: seek error", lump_name);
+	 rc = 1;
+	 goto byebye;
+	 }
+      size_t s = 0;
+      for (size_t n = 0; n < nlines; n++)
+	 {
+	 LDPtr ld = LineDefs + n;
+	 ld->start   = wf->read_i16 ();
+	 ld->end     = wf->read_i16 ();
+	 ld->flags   = wf->read_i16 ();
+	               wf->read_i16 ();  // Unused ?
+	 ld->type    = wf->read_i16 ();
+	 ld->tag     = wf->read_i16 ();
+	               wf->read_i16 ();  // Unused ?
+	 i16 sector1 = wf->read_i16 ();
+	 i16 xofs1   = wf->read_i16 ();
+	 i16 tex1m   = wf->read_i16 ();
+	 i16 tex1u   = wf->read_i16 ();
+	 i16 tex1l   = wf->read_i16 ();
+	               wf->read_i16 ();  // Unused ?
+	 i16 sector2 = wf->read_i16 ();
+	 i16 xofs2   = wf->read_i16 ();
+	 i16 tex2m   = wf->read_i16 ();
+	 i16 tex2u   = wf->read_i16 ();
+	 i16 tex2l   = wf->read_i16 ();
+	 if (sector1 >= 0)			// Create first sidedef
+	    {
+	    ld->sidedef1 = s;
+	    SDPtr sd = SideDefs + s;
+	    sd->xoff = xofs1;
+	    sd->yoff = 0;
+	    memcpy (sd->tex1, texno_texname (tex1u), sizeof sd->tex1);
+	    memcpy (sd->tex2, texno_texname (tex1l), sizeof sd->tex2);
+	    memcpy (sd->tex3, texno_texname (tex1m), sizeof sd->tex3);
+	    sd->sector = sector1;
+	    s++;
+	    }
+	 else  // No first sidedef !
+	    ld->sidedef1 = -1;
+	 if (ld->flags & 0x04)			// Create second sidedef
+	    {
+	    ld->sidedef2 = s;
+	    SDPtr sd = SideDefs + s;
+	    sd->xoff = xofs2;
+	    sd->yoff = 0;
+	    memcpy (sd->tex1, texno_texname (tex2u), sizeof sd->tex1);
+	    memcpy (sd->tex2, texno_texname (tex2l), sizeof sd->tex2);
+	    memcpy (sd->tex3, texno_texname (tex2m), sizeof sd->tex3);
+	    sd->sector = sector2;
+	    s++;
+	    }
+	 else
+	    ld->sidedef2 = -1;
+	 if (wf->error ())
+	    {
+	    err ("%s: error reading line #%d", lump_name, int (n));
+	    rc = 1;
+	    goto byebye;
+	    }
+	 }
+      // (size_t) to silence GCC warning
+      if ((size_t) NumSideDefs > s)  // Almost always true.
+         {
+	 NumSideDefs = s;
+         SideDefs = (SDPtr) ResizeFarMemory (SideDefs,
+	     (unsigned long) NumSideDefs * sizeof (struct SideDef));
+         }
+      if (tex_list)
+         FreeMemory (tex_list);
+      tex_list = 0;
+      ntex = 0;
+      }
+   }
+
+/* Read the vertices. If the wad has been run through a nodes
+   builder, there is a bunch of vertices at the end that are not
+   used by any linedefs. Those vertices have been created by the
+   nodes builder for the segs. We ignore them, because they're
+   useless to the level designer. However, we do NOT ignore
+   unused vertices in the middle because that's where the
+   "string art" bug came from.
+
+   Note that there is absolutely no guarantee that the nodes
+   builders add their own vertices at the end, instead of at the
+   beginning or right in the middle, AFAIK. It's just that they
+   all seem to do that (1). What if some don't ? Well, we would
+   end up with many unwanted vertices in the level data. Nothing
+   that a good CheckCrossReferences() couldn't take care of. */
+{
+verbmsg (" vertices");
+int last_used_vertex = -1;
+for (long n = 0; n < NumLineDefs; n++)
+   {
+   last_used_vertex = y_max (last_used_vertex, LineDefs[n].start);
+   last_used_vertex = y_max (last_used_vertex, LineDefs[n].end);
+   }
+NumVertices = last_used_vertex + 1;
+// This block is only here to warn me if (1) is false.
+{
+  bitvec_c vertex_used (OldNumVertices);
+  for (long n = 0; n < NumLineDefs; n++)
+     {
+     vertex_used.set (LineDefs[n].start);
+     vertex_used.set (LineDefs[n].end);
+     }
+  int unused = 0;
+  for (long n = 0; n <= last_used_vertex; n++)
+     {
+     if (! vertex_used.get (n))
+	unused++;
+     }
+  if (unused > 0)
+     {
+     warn ("this level has unused vertices in the middle.\n");
+     warn ("total %d, tail %d (%d%%), unused %d (",
+	OldNumVertices,
+	OldNumVertices - NumVertices,
+	NumVertices - unused
+	   ? 100 * (OldNumVertices - NumVertices) / (NumVertices - unused)
+	   : 0,
+	unused);
+     int first = 1;
+     for (int n = 0; n <= last_used_vertex; n++)
+        {
+	if (! vertex_used.get (n))
+	   {
+	   if (n == 0 || vertex_used.get (n - 1))
+	      {
+	      if (first)
+	         first = 0;
+	      else
+	         warn (", ");
+	      warn ("%d", n);
+	      }
+	   else if (n == last_used_vertex || vertex_used.get (n + 1))
+	      warn ("-%d", n);
+	   }
+	}
+     warn (")\n");
+     }
+}
+// Now load all the vertices except the unused ones at the end.
+if (NumVertices > 0)
+   {
+   const char *lump_name = "BUG";
+   Vertices = (VPtr) GetFarMemory ((unsigned long) NumVertices
+      * sizeof (struct Vertex));
+   if (yg_level_format == YGLF_ALPHA)  // Doom alpha
+      lump_name = "POINTS";
+   else
+      lump_name = "VERTEXES";
+   dir = FindMasterDir (Level, lump_name);
+   if (dir == 0)
+      goto vertexes_done;		// FIXME isn't that fatal ?
+   {
+   const Wad_file *wf = dir->wadfile;
+   wf->seek (v_offset);
+   if (wf->error ())
+      {
+      err ("%s: seek error", lump_name);
+      rc = 1;
+      goto byebye;
+      }
+   MapMaxX = -32767;
+   MapMaxY = -32767;
+   MapMinX = 32767;
+   MapMinY = 32767;
+   for (long n = 0; n < NumVertices; n++)
+      {
+      i16 val;
+      wf->read_i16 (&val);
+      if (val < MapMinX)
+	 MapMinX = val;
+      if (val > MapMaxX)
+	 MapMaxX = val;
+      Vertices[n].x = val;
+      wf->read_i16 (&val);
+      if (val < MapMinY)
+	 MapMinY = val;
+      if (val > MapMaxY)
+	 MapMaxY = val;
+      Vertices[n].y = val;
+      if (wf->error ())
+	 {
+	 err ("%s: error reading vertex #%ld", lump_name, n);
+	 rc = 1;
+	 goto byebye;
+	 }
+      }
+   }
+   vertexes_done:
+   ;
+   }
+}
+
+// Ignore SEGS, SSECTORS and NODES
+
+// Read SECTORS
+{
+const char *lump_name = "SECTORS";
+verbmsg (" sectors\n");
+dir = FindMasterDir (Level, lump_name);
+if (yg_level_format != YGLF_ALPHA)
+   {
+   if (dir)
+      {
+      NumSectors = (int) (dir->dir.size / WAD_SECTOR_BYTES);
+      if ((i32) (NumSectors * WAD_SECTOR_BYTES) != dir->dir.size)
+	 warn ("the %s lump has a weird size."
+	   " The wad might be corrupt.\n", lump_name);
+      }
+   else
+      NumSectors = 0;
+   if (NumSectors > 0)
+      {
+      Sectors = (SPtr) GetFarMemory ((unsigned long) NumSectors
+	 * sizeof (struct Sector));
+      const Wad_file *wf = dir->wadfile;
+      wf->seek (dir->dir.start);
+      if (wf->error ())
+	 {
+	 err ("%s: seek error", lump_name);
+	 rc = 1;
+	 goto byebye;
+	 }
+      for (long n = 0; n < NumSectors; n++)
+	 {
+	 wf->read_i16   (&Sectors[n].floorh);
+	 wf->read_i16   (&Sectors[n].ceilh);
+	 wf->read_bytes (&Sectors[n].floort, WAD_FLAT_NAME);
+	 wf->read_bytes (&Sectors[n].ceilt,  WAD_FLAT_NAME);
+	 wf->read_i16   (&Sectors[n].light);
+	 wf->read_i16   (&Sectors[n].special);
+	 wf->read_i16   (&Sectors[n].tag);
+	 if (wf->error ())
+	    {
+	    err ("%s: error reading sector #%ld", lump_name, n);
+	    rc = 1;
+	    goto byebye;
+	    }
+	 }
+      }
+   }
+else  // Doom alpha--a wholly different SECTORS format
+   {
+   i32  *offset_table = 0;
+   i32   nsectors     = 0;
+   i32   nflatnames   = 0;
+   char *flatnames    = 0;
+   if (dir == 0)
+      {
+      warn ("%s: lump not found in directory\n", lump_name);  // FIXME fatal ?
+      goto sectors_alpha_done;
+      }
+   {
+   const Wad_file *wf = dir->wadfile;
+   wf->seek (dir->dir.start);
+   if (wf->error ())
+      {
+      err ("%s: seek error", lump_name);
+      rc = 1;
+      goto byebye;
+      }
+   wf->read_i32 (&nsectors);
+   if (wf->error ())
+      {
+      err ("%s: error reading sector count", lump_name);
+      rc = 1;
+      goto byebye;
+      }
+   if (nsectors < 0)
+      {
+      warn ("Negative sector count. Clamping to 0.\n");
+      nsectors = 0;
+      }
+   NumSectors = nsectors;
+   Sectors = (SPtr) GetFarMemory ((unsigned long) NumSectors
+      * sizeof (struct Sector));
+   offset_table = new i32[nsectors];
+   for (size_t n = 0; n < (size_t) nsectors; n++)
+      wf->read_i32 (offset_table + n);
+   if (wf->error ())
+      {
+      err ("%s: error reading offsets table", lump_name);
+      rc = 1;
+      goto sectors_alpha_done;
+      }
+   // Load FLATNAME
+   {
+      const char *lump_name = "FLATNAME";
+      bool success = false;
+      MDirPtr dir2 = FindMasterDir (Level, lump_name);
+      if (dir2 == 0)
+	 {
+	 warn ("%s: lump not found in directory\n", lump_name);
+	 goto flatname_done;		// FIXME warn ?
+	 }
+      {
+      const Wad_file *wf = dir2->wadfile;
+      wf->seek (dir2->dir.start);
+      if (wf->error ())
+	 {
+	 warn ("%s: seek error\n", lump_name);
+	 goto flatname_done;
+	 }
+      wf->read_i32 (&nflatnames);
+      if (wf->error ())
+	 {
+	 warn ("%s: error reading flat name count\n", lump_name);
+	 nflatnames = 0;
+	 goto flatname_done;
+	 }
+      if (nflatnames < 0 || nflatnames > 32767)
+	 {
+	 warn ("%s: bad flat name count, giving up\n", lump_name);
+	 nflatnames = 0;
+	 goto flatname_done;
+	 }
+      else
+	 {
+	 flatnames = new char[WAD_FLAT_NAME * nflatnames];
+	 wf->read_bytes (flatnames, WAD_FLAT_NAME * nflatnames);
+	 if (wf->error ())
+	    {
+	    warn ("%s: error reading flat names\n", lump_name);
+	    nflatnames = 0;
+	    goto flatname_done;
+	    }
+	 success = true;
+	 }
+      }
+      flatname_done:
+      if (! success)
+	 warn ("%s: errors found, you'll have to do without flat names\n",
+	       lump_name);
+   }
+   for (size_t n = 0; n < (size_t) nsectors; n++)
+      {
+      wf->seek (dir->dir.start + offset_table[n]);
+      if (wf->error ())
+	 {
+	 err ("%s: seek error", lump_name);
+	 rc = 1;
+	 goto sectors_alpha_done;
+	 }
+      i16 index;
+      wf->read_i16 (&Sectors[n].floorh);
+      wf->read_i16 (&Sectors[n].ceilh );
+      wf->read_i16 (&index);
+      if (nflatnames && flatnames && index >= 0 && index < nflatnames)
+	 memcpy (Sectors[n].floort, flatnames + WAD_FLAT_NAME * index,
+	     WAD_FLAT_NAME);
+      else
+	 strcpy (Sectors[n].floort, "unknown");
+      wf->read_i16 (&index);
+      if (nflatnames && flatnames && index >= 0 && index < nflatnames)
+	 memcpy (Sectors[n].ceilt, flatnames + WAD_FLAT_NAME * index,
+	     WAD_FLAT_NAME);
+      else
+	 strcpy (Sectors[n].ceilt, "unknown");
+      wf->read_i16 (&Sectors[n].light);
+      wf->read_i16 (&Sectors[n].special);
+      wf->read_i16 (&Sectors[n].tag);
+      // Don't know what the tail is for. Ignore it.
+      if (wf->error ())
+	 {
+	 err ("%s: error reading sector #%ld", lump_name, long (n));
+	 rc = 1;
+	 goto sectors_alpha_done;
+	 }
+      }
+   }
+   
+   sectors_alpha_done:
+   if (offset_table != 0)
+      delete[] offset_table;
+   if (flatnames != 0)
+      delete[] flatnames;
+   if (rc != 0)
+      goto byebye;
+   }
+}
+
+/* Sanity checking on sidedefs: the sector must exist. I don't
+   make this a fatal error, though, because it's not exceptional
+   to find wads with unused sidedefs with a sector# of -1. Well
+   known ones include dyst3 (MAP06, MAP07, MAP08), mm (MAP16),
+   mm2 (MAP13, MAP28) and requiem (MAP03, MAP08, ...). */
+for (long n = 0; n < NumSideDefs; n++)
+   {
+   if (outside (SideDefs[n].sector, 0, NumSectors - 1))
+      warn ("sidedef %ld has bad sector number %d\n",
+	 n, SideDefs[n].sector);
+   }
+
+// Ignore REJECT and BLOCKMAP
+
+// Silly statistics
+verbmsg ("  %d things, %d vertices, %d linedefs, %d sidedefs, %d sectors\n",
+   (int) NumThings, (int) NumVertices, (int) NumLineDefs,
+   (int) NumSideDefs, (int) NumSectors);
+verbmsg ("  Map: (%d,%d)-(%d,%d)\n", MapMinX, MapMinY, MapMaxX, MapMaxY);
+
+byebye:
+if (rc != 0)
+   err ("%s: errors found, giving up", levelname);
+return rc;
+}
+
+
+
+/*
+   forget the level data
+*/
+
+void ForgetLevelData () /* SWAP! */
+{
+/* forget the things */
+ObjectsNeeded (OBJ_THINGS, 0);
+NumThings = 0;
+if (Things != 0)
+   FreeFarMemory (Things);
+Things = 0;
+things_angles++;
+things_types++;
+
+/* forget the vertices */
+ObjectsNeeded (OBJ_VERTICES, 0);
+NumVertices = 0;
+if (Vertices != 0)
+   FreeFarMemory (Vertices);
+Vertices = 0;
+
+/* forget the linedefs */
+ObjectsNeeded (OBJ_LINEDEFS, 0);
+NumLineDefs = 0;
+if (LineDefs != 0)
+   FreeFarMemory (LineDefs);
+LineDefs = 0;
+
+/* forget the sidedefs */
+ObjectsNeeded (OBJ_SIDEDEFS, 0);
+NumSideDefs = 0;
+if (SideDefs != 0)
+   FreeFarMemory (SideDefs);
+SideDefs = 0;
+
+/* forget the sectors */
+ObjectsNeeded (OBJ_SECTORS, 0);
+NumSectors = 0;
+if (Sectors != 0)
+   FreeFarMemory (Sectors);
+Sectors = 0;
+ObjectsNeeded (0);
+}
+
+
+/*
+ *	Save the level data to a pwad file
+ *	The name of the level is always obtained from
+ *	<level_name>, whether or not the level was created from
+ *	scratch.
+ *
+ *	The previous contents of the pwad file are lost. Yes, it
+ *	sucks but it's not easy to fix.
+ *
+ *	The lumps are always written in the same order, the same
+ *	as the one in the Doom iwad. The length field of the
+ *	marker lump is always set to 0. Its offset field is
+ *	always set to the offset of the first lump of the level
+ *	(THINGS).
+ *
+ *	If the level has been created by editing an existing
+ *	level and has not been changed in a way that calls for a
+ *	rebuild of the nodes, the VERTEXES, SEGS, SSECTORS,
+ *	NODES, REJECT and BLOCKMAP lumps are copied from the
+ *	original level. Otherwise, they are created with a
+ *	length of 0 bytes and an offset equal to the offset of
+ *	the previous lump plus its length.
+ *
+ *	Returns 0 on success and non-zero on failure (see errno).
+ */
+int SaveLevelData (const char *outfile, const char *level_name) /* SWAP! */
+{
+FILE   *file;
+MDirPtr dir;
+int     n;
+long	lump_offset[WAD_LL__];
+size_t	lump_size[WAD_LL__];
+wad_level_lump_no_t l;
+
+if (yg_level_format == YGLF_HEXEN || ! strcmp (Game, "hexen"))
+   {
+   Notify (-1, -1, "I refuse to save. Hexen mode is still",
+                   "too badly broken. You would lose data.");
+   return 1;
+   }
+if (! level_name || ! levelname2levelno (level_name))
+   {
+   nf_bug ("SaveLevelData: bad level_name \"%s\", using \"E1M1\" instead.",
+       level_name);
+   level_name = "E1M1";
+   }
+DisplayMessage (-1, -1, "Saving data to \"%s\"...", outfile);
+LogMessage (": Saving data to \"%s\"...\n", outfile);
+if ((file = fopen (outfile, "wb")) == NULL)
+   {
+   char buf1[81];
+   char buf2[81];
+   y_snprintf (buf1, sizeof buf1, "Can't open \"%.64s\"", outfile);
+   y_snprintf (buf2, sizeof buf1, "for writing (%.64s)",  strerror (errno));
+   Notify (-1, -1, buf1, buf2);
+   return 1;
+   }
+
+/* Can we reuse the old nodes ? Not if this is a new level from
+   scratch or if the structure of the level has changed. If the
+   level comes from an alpha version of Doom, we can't either
+   because that version of Doom didn't have SEGS, NODES, etc. */
+bool reuse_nodes = Level
+  && ! MadeMapChanges
+  && yg_level_format != YGLF_ALPHA;
+
+// Write the pwad header
+WriteBytes (file, "PWAD", 4);		// Pwad file
+file_write_i32 (file, WAD_LL__);	// Number of entries = 11
+file_write_i32 (file, 0);		// Fix this up later
+if (Level)
+   dir = Level->next;
+else
+   dir = 0;  // Useless except to trap accidental dereferences
+
+// The label (EnMm or MAPnm)
+l = WAD_LL_LABEL;
+lump_offset[l] = ftell (file);	// By definition
+lump_size[l]   =  0;		// By definition
+ 
+// Write the THINGS lump
+l = WAD_LL_THINGS;
+lump_offset[l] = ftell (file);
+ObjectsNeeded (OBJ_THINGS, 0);
+for (n = 0; n < NumThings; n++)
+   {
+   file_write_i16 (file, Things[n].xpos );
+   file_write_i16 (file, Things[n].ypos );
+   file_write_i16 (file, Things[n].angle);
+   file_write_i16 (file, Things[n].type );
+   file_write_i16 (file, Things[n].when );
+   }
+lump_size[l] = ftell (file) - lump_offset[l];
+if (Level)
+   dir = dir->next;
+
+// Write the LINEDEFS lump
+l = WAD_LL_LINEDEFS;
+lump_offset[WAD_LL_LINEDEFS] = ftell (file);
+ObjectsNeeded (OBJ_LINEDEFS, 0);
+for (n = 0; n < NumLineDefs; n++)
+   {
+   file_write_i16 (file, LineDefs[n].start   );
+   file_write_i16 (file, LineDefs[n].end     );
+   file_write_i16 (file, LineDefs[n].flags   );
+   file_write_i16 (file, LineDefs[n].type    );
+   file_write_i16 (file, LineDefs[n].tag     );
+   file_write_i16 (file, LineDefs[n].sidedef1);
+   file_write_i16 (file, LineDefs[n].sidedef2);
+   }
+lump_size[l] = ftell (file) - lump_offset[l];
+if (Level)
+   dir = dir->next;
+
+// Write the SIDEDEFS lump
+l = WAD_LL_SIDEDEFS;
+lump_offset[l] = ftell (file);
+ObjectsNeeded (OBJ_SIDEDEFS, 0);
+for (n = 0; n < NumSideDefs; n++)
+   {
+   file_write_i16 (file, SideDefs[n].xoff);
+   file_write_i16 (file, SideDefs[n].yoff);
+   WriteBytes     (file, &(SideDefs[n].tex1), WAD_TEX_NAME);
+   WriteBytes     (file, &(SideDefs[n].tex2), WAD_TEX_NAME);
+   WriteBytes     (file, &(SideDefs[n].tex3), WAD_TEX_NAME);
+   file_write_i16 (file, SideDefs[n].sector);
+   }
+lump_size[l] = ftell (file) - lump_offset[l];
+if (Level)
+   dir = dir->next;
+
+// Write the VERTEXES lump
+l = WAD_LL_VERTEXES;
+lump_offset[WAD_LL_VERTEXES] = ftell (file);
+if (reuse_nodes)
+   {
+   /* Copy the vertices */
+   ObjectsNeeded (0);
+   const Wad_file *wf = dir->wadfile;
+   wf->seek (dir->dir.start);
+   if (wf->error ())
+      {
+      warn ("%s: seek error\n", wad_level_lump[l]);
+      }
+   copy_bytes (file, wf->fp, dir->dir.size);
+   }
+else
+   {
+   /* Write the vertices */
+   ObjectsNeeded (OBJ_VERTICES, 0);
+   for (n = 0; n < NumVertices; n++)
+      {
+      file_write_i16 (file, Vertices[n].x);
+      file_write_i16 (file, Vertices[n].y);
+      }
+   }
+lump_size[l] = ftell (file) - lump_offset[l];
+if (Level)
+   dir = dir->next;
+
+// Write the SEGS, SSECTORS and NODES lumps
+for (n = 0; n < 3; n++)
+   {
+   if (n == 0)
+      l = WAD_LL_SEGS;
+   else if (n == 1)
+      l = WAD_LL_SSECTORS;
+   else if (n == 2)
+      l = WAD_LL_NODES;
+   lump_offset[l] = ftell (file);
+   if (reuse_nodes)
+      {
+      const Wad_file *wf = dir->wadfile;
+      wf->seek (dir->dir.start);
+      if (wf->error ())
+	 {
+	 warn ("%s: seek error\n", wad_level_lump[l]);
+	 }
+      copy_bytes (file, wf->fp, dir->dir.size);
+      }
+   lump_size[l] = ftell (file) - lump_offset[l];
+   if (Level)
+      dir = dir->next;
+   }
+
+// Write the SECTORS lump
+l = WAD_LL_SECTORS;
+lump_offset[l] = ftell (file);
+ObjectsNeeded (OBJ_SECTORS, 0);
+for (n = 0; n < NumSectors; n++)
+   {
+   file_write_i16 (file, Sectors[n].floorh);
+   file_write_i16 (file, Sectors[n].ceilh );
+   WriteBytes     (file, Sectors[n].floort, WAD_FLAT_NAME);
+   WriteBytes     (file, Sectors[n].ceilt,  WAD_FLAT_NAME);
+   file_write_i16 (file, Sectors[n].light  );
+   file_write_i16 (file, Sectors[n].special);
+   file_write_i16 (file, Sectors[n].tag    );
+   }
+lump_size[l] = ftell (file) - lump_offset[l];
+if (Level)
+   dir = dir->next;
+
+// Write the REJECT lump
+l = WAD_LL_REJECT;
+lump_offset[l] = ftell (file);
+if (reuse_nodes)
+   {
+   /* Copy the REJECT data */
+   ObjectsNeeded (0);
+   const Wad_file *wf = dir->wadfile;
+   wf->seek (dir->dir.start);
+   if (wf->error ())
+      {
+      warn ("%s: seek error\n", wad_level_lump[l]);
+      }
+   copy_bytes (file, wf->fp, dir->dir.size);
+   }
+lump_size[l] = ftell (file) - lump_offset[l];
+if (Level)
+   dir = dir->next;
+
+// Write the BLOCKMAP lump
+l = WAD_LL_BLOCKMAP;
+lump_offset[l] = ftell (file);
+if (reuse_nodes)
+   {
+   ObjectsNeeded (0);
+   const Wad_file *wf = dir->wadfile;
+   wf->seek (dir->dir.start);
+   if (wf->error ())
+      {
+      warn ("%s: seek error\n", wad_level_lump[l]);
+      }
+   copy_bytes (file, wf->fp, dir->dir.size);
+   }
+lump_size[l] = ftell (file) - lump_offset[l];
+if (Level)
+   dir = dir->next;
+
+// Write the actual directory
+long dir_offset = ftell (file);
+for (int L = 0; L < (int) WAD_LL__; L++)
+   {
+   file_write_i32 (file, lump_offset[L]);
+   file_write_i32 (file, lump_size[L]);
+   if (L == (int) WAD_LL_LABEL)
+      file_write_name (file, level_name);
+   else
+      file_write_name (file, wad_level_lump[L].name);
+   }
+
+/* Fix up the directory start information */
+if (fseek (file, 8, SEEK_SET))
+   {
+   char buf1[81];
+   char buf2[81];
+   y_snprintf (buf1, sizeof buf1, "%.64s: seek error", outfile);
+   y_snprintf (buf2, sizeof buf2, "(%.64s)",           strerror (errno));
+   Notify (-1, -1, buf1, buf2);
+   fclose (file);
+   return 1;
+   }
+file_write_i32 (file, dir_offset);
+
+/* Close the file */
+if (fclose (file))
+   {
+   char buf1[81];
+   char buf2[81];
+   y_snprintf (buf1, sizeof buf1, "%.64s: write error", outfile);
+   y_snprintf (buf2, sizeof buf2, "(%.64s)",            strerror (errno));
+   Notify (-1, -1, buf1, buf2);
+   return 1;
+   }
+
+/* The file is now up to date */
+if (! Level || MadeMapChanges)
+   remind_to_build_nodes = 1;
+MadeChanges = 0;
+MadeMapChanges = 0;
+ObjectsNeeded (0);
+
+/* Update pointers in Master Directory */
+OpenPatchWad (outfile);
+
+/* This should free the old "*.bak" file */
+CloseUnusedWadFiles ();
+
+/* Update MapMinX, MapMinY, MapMaxX, MapMaxY */
+// Probably not necessary anymore -- AYM 1999-04-05
+ObjectsNeeded (OBJ_VERTICES, 0);
+update_level_bounds ();
+return 0;
+}
+
+
+/*
+ *	flat_list_entry_cmp
+ *	Function used by qsort() to sort the flat_list_entry array
+ *	by ascending flat name.
+ */
+static int flat_list_entry_cmp (const void *a, const void *b)
+{
+return y_strnicmp (
+    ((const flat_list_entry_t *) a)->name,
+    ((const flat_list_entry_t *) b)->name,
+    WAD_FLAT_NAME);
+}
+
+
+/*
+   function used by qsort to sort the texture names
+*/
+static int SortTextures (const void *a, const void *b)
+{
+return y_strnicmp (*((const char *const *)a), *((const char *const *)b),
+    WAD_TEX_NAME);
+}
+
+
+/*
+   read the texture names
+*/
+void ReadWTextureNames ()
+{
+MDirPtr dir;
+int n;
+i32 val;
+
+verbmsg ("Reading texture names\n");
+
+// Doom alpha 0.4 : "TEXTURES", no names
+if (yg_texture_lumps == YGTL_TEXTURES
+ && yg_texture_format == YGTF_NAMELESS)
+   {
+   const char *lump_name = "TEXTURES";
+   dir = FindMasterDir (MasterDir, lump_name);
+   if (dir == NULL)
+      {
+      warn ("%s: lump not found in directory\n", lump_name);
+      goto textures04_done;
+      }
+   {
+   const Wad_file *wf = dir->wadfile;
+   wf->seek (dir->dir.start);
+   if (wf->error ())
+      {
+      warn ("%s: seek error\n", lump_name);
+      goto textures04_done;
+      }
+   wf->read_i32 (&val);
+   if (wf->error ())
+      {
+      warn ("%s: error reading texture count\n", lump_name);
+      goto textures04_done;
+      }
+   NumWTexture = (int) val + 1;
+   WTexture = (char **) GetMemory ((long) NumWTexture * sizeof *WTexture);
+   WTexture[0] = (char *) GetMemory (WAD_TEX_NAME + 1);
+   strcpy (WTexture[0], "-");
+   if (WAD_TEX_NAME < 7) nf_bug ("WAD_TEX_NAME too small");  // Sanity
+   for (long n = 0; n < val; n++)
+      {
+      WTexture[n + 1] = (char *) GetMemory (WAD_TEX_NAME + 1);
+      if (n > 9999)
+	 {
+	 warn ("more than 10,000 textures. Ignoring excess.\n");
+	 break;
+	 }
+      sprintf (WTexture[n + 1], "TEX%04ld", n);
+      }
+   }
+   textures04_done:
+   ;
+   }
+
+// Doom alpha 0.5 : only "TEXTURES"
+else if (yg_texture_lumps == YGTL_TEXTURES
+      && (yg_texture_format == YGTF_NORMAL
+	  || yg_texture_format == YGTF_STRIFE11))
+   {
+   const char *lump_name = "TEXTURES";
+   i32 *offsets = 0;
+   dir = FindMasterDir (MasterDir, lump_name);
+   if (dir == NULL)  // In theory it always exists, though
+      {
+      warn ("%s: lump not found in directory\n", lump_name);
+      goto textures05_done;
+      }
+   {
+   const Wad_file *wf = dir->wadfile;
+   wf->seek (dir->dir.start);
+   if (wf->error ())
+      {
+      warn ("%s: seek error\n", lump_name);
+      goto textures05_done;
+      }
+   wf->read_i32 (&val);
+   if (wf->error ())
+      {
+      warn ("%s: error reading texture count\n", lump_name);
+      goto textures05_done;
+      }
+   NumWTexture = (int) val + 1;
+   /* read in the offsets for texture1 names */
+   offsets = (i32 *) GetMemory ((long) NumWTexture * 4);
+   wf->read_i32 (offsets + 1, NumWTexture - 1);
+   if (wf->error ())
+      {
+      warn ("%s: error reading offsets table\n", lump_name);
+      goto textures05_done;
+      }
+   /* read in the actual names */
+   WTexture = (char **) GetMemory ((long) NumWTexture * sizeof (char *));
+   WTexture[0] = (char *) GetMemory (WAD_TEX_NAME + 1);
+   strcpy (WTexture[0], "-");
+   for (n = 1; n < NumWTexture; n++)
+      {
+      WTexture[n] = (char *) GetMemory (WAD_TEX_NAME + 1);
+      long offset = dir->dir.start + offsets[n];
+      wf->seek (offset);
+      if (wf->error ())
+	 {
+	 warn ("%s: error seeking to  error\n", lump_name);
+	 goto textures05_done;		// FIXME cleanup
+	 }
+      wf->read_bytes (WTexture[n], WAD_TEX_NAME);
+      if (wf->error ())
+	 {
+	 warn ("%s: error reading texture names\n", lump_name);
+	 goto textures05_done;		// FIXME cleanup
+	 }
+      WTexture[n][WAD_TEX_NAME] = '\0';
+      }
+   }
+   textures05_done:
+   if (offsets != 0)
+      FreeMemory (offsets);
+   }
+// Other iwads : "TEXTURE1" and possibly "TEXTURE2"
+else if (yg_texture_lumps == YGTL_NORMAL
+      && (yg_texture_format == YGTF_NORMAL
+	  || yg_texture_format == YGTF_STRIFE11))
+   {
+   const char *lump_name = "TEXTURE1";
+   i32 *offsets = 0;
+   dir = FindMasterDir (MasterDir, lump_name);
+   if (dir != NULL)  // In theory it always exists, though
+      {
+      const Wad_file *wf = dir->wadfile;
+      wf->seek (dir->dir.start);
+      if (wf->error ())
+	 {
+	 warn ("%s: seek error\n", lump_name);
+	 // FIXME
+	 }
+      wf->read_i32 (&val);
+      if (wf->error ())
+      {
+	// FIXME
+      }
+      NumWTexture = (int) val + 1;
+      /* read in the offsets for texture1 names */
+      offsets = (i32 *) GetMemory ((long) NumWTexture * 4);
+      wf->read_i32 (offsets + 1, NumWTexture - 1);
+      {
+	// FIXME
+      }
+      /* read in the actual names */
+      WTexture = (char **) GetMemory ((long) NumWTexture * sizeof (char *));
+      WTexture[0] = (char *) GetMemory (WAD_TEX_NAME + 1);
+      strcpy (WTexture[0], "-");
+      for (n = 1; n < NumWTexture; n++)
+	 {
+	 WTexture[n] = (char *) GetMemory (WAD_TEX_NAME + 1);
+	 wf->seek (dir->dir.start + offsets[n]);
+	 if (wf->error ())
+	    {
+	    warn ("%s: seek error\n", lump_name);
+	    // FIXME
+	    }
+	 wf->read_bytes (WTexture[n], WAD_TEX_NAME);
+	 if (wf->error ())
+	    {
+	      // FIXME
+	    }
+	 WTexture[n][WAD_TEX_NAME] = '\0';
+	 }
+      FreeMemory (offsets);
+      }
+   {
+   dir = FindMasterDir (MasterDir, "TEXTURE2");
+   if (dir)  /* Doom II has no TEXTURE2 */
+      {
+      const Wad_file *wf = dir->wadfile;
+      wf->seek (dir->dir.start);
+      if (wf->error ())
+	 {
+	 warn ("%s: seek error\n", lump_name);
+	 // FIXME
+	 }
+      wf->read_i32 (&val);
+      if (wf->error ())
+      {
+	// FIXME
+      }
+      /* read in the offsets for texture2 names */
+      offsets = (i32 *) GetMemory ((long) val * 4);
+      wf->read_i32 (offsets, val);
+      if (wf->error ())
+      {
+	// FIXME
+      }
+      /* read in the actual names */
+      WTexture = (char **) ResizeMemory (WTexture,
+	 (NumWTexture + val) * sizeof (char *));
+      for (n = 0; n < val; n++)
+	 {
+	 WTexture[NumWTexture + n] = (char *) GetMemory (WAD_TEX_NAME + 1);
+	 wf->seek (dir->dir.start + offsets[n]);
+	 if (wf->error ())
+	    {
+	    warn ("%s: seek error\n", lump_name);
+	    // FIXME
+	    }
+	 wf->read_bytes (WTexture[NumWTexture + n], WAD_TEX_NAME);
+	 if (wf->error ())
+	   ; // FIXME
+	 WTexture[NumWTexture + n][WAD_TEX_NAME] = '\0';
+	 }
+      NumWTexture += val;
+      FreeMemory (offsets);
+      }
+   }
+   }
+else
+   nf_bug ("Invalid texture_format/texture_lumps combination.");
+
+/* sort the names */
+qsort (WTexture, NumWTexture, sizeof (char *), SortTextures);
+}
+
+
+
+/*
+   forget the texture names
+*/
+
+void ForgetWTextureNames ()
+{
+int n;
+
+/* forget all names */
+for (n = 0; n < NumWTexture; n++)
+   FreeMemory (WTexture[n]);
+
+/* forget the array */
+NumWTexture = 0;
+FreeMemory (WTexture);
+}
+
+
+
+/*
+   read the flat names
+*/
+
+void ReadFTextureNames ()
+{
+MDirPtr dir;
+int n;
+
+verbmsg ("Reading flat names");
+NumFTexture = 0;
+
+for (dir = MasterDir; (dir = FindMasterDir (dir, "F_START", "FF_START"));)
+   {
+   bool ff_start = ! y_strnicmp (dir->dir.name, "FF_START", WAD_NAME);
+   MDirPtr dir0;
+   /* count the names */
+   dir = dir->next;
+   dir0 = dir;
+   for (n = 0; dir && y_strnicmp (dir->dir.name, "F_END", WAD_NAME)
+	 && (! ff_start || y_strnicmp (dir->dir.name, "FF_END", WAD_NAME));
+	 dir = dir->next)
+      {
+      if (dir->dir.start == 0 || dir->dir.size == 0)
+	 {
+	 if (! (toupper (dir->dir.name[0]) == 'F'
+	     && (dir->dir.name[1] == '1'
+	      || dir->dir.name[1] == '2'
+	      || dir->dir.name[1] == '3'
+	      || toupper (dir->dir.name[1]) == 'F')
+	     && dir->dir.name[2] == '_'
+	     && (! y_strnicmp (dir->dir.name + 3, "START", WAD_NAME - 3)
+		 || ! y_strnicmp (dir->dir.name + 3, "END", WAD_NAME - 3))))
+	    warn ("unexpected label \"%.*s\" among flats.\n",
+		  WAD_NAME, dir->dir.name);
+	 continue;
+	 }
+      if (dir->dir.size != 4096)
+	 warn ("flat \"%.*s\" has weird size %lu."
+	     " Using 4096 instead.\n",
+	       WAD_NAME, dir->dir.name, (unsigned long) dir->dir.size);
+      n++;
+      }
+   /* If FF_START/FF_END followed by F_END (mm2.wad), advance
+      past F_END. In fact, this does not work because the F_END
+      that follows has been snatched by OpenPatchWad(), that
+      thinks it replaces the F_END from the iwad. OpenPatchWad()
+      needs to be kludged to take this special case into
+      account. Fortunately, the only consequence is a useless
+      "this wad uses FF_END" warning. -- AYM 1999-07-10 */
+   if (ff_start && dir && ! y_strnicmp (dir->dir.name, "FF_END", WAD_NAME))
+      if (dir->next && ! y_strnicmp (dir->next->dir.name, "F_END", WAD_NAME))
+         dir = dir->next;
+
+   verbmsg (" FF_START/%s %d", dir->dir.name, n);
+   if (dir && ! y_strnicmp (dir->dir.name, "FF_END", WAD_NAME))
+      warn ("this wad uses FF_END. That won't work with Doom."
+	 " Use F_END instead.\n");
+   /* get the actual names from master dir. */
+   flat_list = (flat_list_entry_t *) ResizeMemory (flat_list,
+      (NumFTexture + n) * sizeof *flat_list);
+   for (size_t m = NumFTexture; m < NumFTexture + n; dir0 = dir0->next)
+      {
+      // Skip all labels.
+      if (dir0->dir.start == 0
+	 || dir0->dir.size == 0
+	 || (toupper (dir0->dir.name[0]) == 'F'
+	     && (dir0->dir.name[1] == '1'
+	      || dir0->dir.name[1] == '2'
+	      || dir0->dir.name[1] == '3'
+	      || toupper (dir0->dir.name[1]) == 'F')
+	     && dir0->dir.name[2] == '_'
+	     && (! y_strnicmp (dir0->dir.name + 3, "START", WAD_NAME - 3)
+		 || ! y_strnicmp (dir0->dir.name + 3, "END", WAD_NAME - 3))
+	     ))
+	 continue;
+      *flat_list[m].name = '\0';
+      strncat (flat_list[m].name, dir0->dir.name, sizeof flat_list[m].name - 1);
+      flat_list[m].wadfile = dir0->wadfile;
+      flat_list[m].offset  = dir0->dir.start;
+      m++;
+      }
+   NumFTexture += n;
+   }
+
+verbmsg ("\n");
+
+/* sort the flats by names */
+qsort (flat_list, NumFTexture, sizeof *flat_list, flat_list_entry_cmp);
+
+/* Eliminate all but the last duplicates of a flat. Suboptimal.
+   Would be smarter to start by the end. */
+for (size_t n = 0; n < NumFTexture; n++)
+   {
+   size_t m = n;
+   while (m + 1 < NumFTexture
+     && ! flat_list_entry_cmp (flat_list + n, flat_list + m + 1))
+       m++;
+   // m now contains the index of the last duplicate
+   int nduplicates = m - n;
+   if (nduplicates > 0)
+      {
+      memmove (flat_list + n, flat_list + m,
+                                      (NumFTexture - m) * sizeof *flat_list);
+      NumFTexture -= nduplicates;
+      // Note that I'm too lazy to resize flat_list...
+      }
+   }
+}
+
+
+/*
+ *	is_flat_name_in_list
+ *	FIXME should use bsearch()
+ */
+int is_flat_name_in_list (const char *name)
+{
+  if (! flat_list)
+    return 0;
+  for (size_t n = 0; n < NumFTexture; n++)
+    if (! y_strnicmp (name, flat_list[n].name, WAD_FLAT_NAME))
+      return 1;
+  return 0;
+}
+
+
+/*
+   forget the flat names
+*/
+
+void ForgetFTextureNames ()
+{
+NumFTexture = 0;
+FreeMemory (flat_list);
+flat_list = 0;
+}
+
+
+/*
+ *	update_level_bounds - update Map{Min,Max}{X,Y}
+ */
+void update_level_bounds ()
+{
+MapMaxX = -32767;
+MapMaxY = -32767;
+MapMinX = 32767;
+MapMinY = 32767;
+for (obj_no_t n = 0; n < NumVertices; n++)
+   {
+   int x = Vertices[n].x;
+   if (x < MapMinX)
+      MapMinX = x;
+   if (x > MapMaxX)
+      MapMaxX = x;
+   int y = Vertices[n].y;
+   if (y < MapMinY)
+      MapMinY = y;
+   if (y > MapMaxY)
+      MapMaxY = y;
+   }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/levels.h	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,92 @@
+/*
+ *	levels.h
+ *	BW & RQ sometime in 1993 or 1994
+ *	FIXME all those variables should become members of a
+ *	"Level" class.
+ */
+
+
+#ifndef YH_LEVELS  /* Prevent multiple inclusion */
+#define YH_LEVELS  /* Prevent multiple inclusion */
+
+
+#include "wstructs.h"
+#include "things.h"
+
+
+// Defined in levels.cc
+extern MDirPtr Level;		/* master dictionary entry for the level */
+
+extern int   NumThings;		/* number of things */
+extern TPtr  Things;		/* things data */
+extern int   NumLineDefs;	/* number of linedefs */
+extern LDPtr LineDefs;		/* linedefs data */
+extern int   NumSideDefs;	/* number of sidedefs */
+extern SDPtr SideDefs;		/* sidedefs data */
+extern int   NumVertices;	/* number of vertices */
+extern VPtr  Vertices;		/* vertices data */
+extern int   NumSegs;		/* number of segments */
+extern int   NumSectors;	/* number of sectors */
+extern SPtr  Sectors;		/* sectors data */
+
+// FIXME should be somewhere else
+extern int   NumWTexture;	/* number of wall textures */
+extern char  **WTexture;	/* array of wall texture names */
+extern size_t NumFTexture;	/* number of floor/ceiling textures */
+typedef struct
+{
+  char            name[WAD_NAME + 1];	// Name of flat
+  const Wad_file *wadfile;		// Pointer on wad where flat comes from
+  i32             offset;		// Offset of flat in wad
+} flat_list_entry_t;			// Length is implicit (always 4096)
+extern flat_list_entry_t *flat_list;	// List of all flats in the directory
+
+extern int   MapMaxX;		/* maximum X value of map */
+extern int   MapMaxY;		/* maximum Y value of map */
+extern int   MapMinX;		/* minimum X value of map */
+extern int   MapMinY;		/* minimum Y value of map */
+extern bool  MadeChanges;	/* made changes? */
+extern bool  MadeMapChanges;	/* made changes that need rebuilding? */
+
+extern unsigned long things_angles;  /* Used to know whether a list of
+				   things sorted by type and angle would
+				   need to be rebuilt. Incremented
+				   whenever a thing is created, deleted
+				   or has its type or angle changed.
+				   Presently, no such list exists but
+				   there will be one if
+				   draw_things_sprites() ever draws
+				   sprites according to their angles. */
+
+extern unsigned long things_types;  /* Used to know whether the list of
+				   things sorted by type that drawmap.cc
+				   maintains should be rebuilt.
+				   Incremented whenever a thing is
+				   created, deleted or has its type
+				   changed. */
+
+extern char Level_name[WAD_NAME + 1]; /* The name of the level (E.G.
+				   "MAP01" or "E1M1"), followed by a
+				   NUL. If the Level has been created as
+				   the result of a "c" command with no
+				   argument, an empty string. The name
+				   is not necesarily in upper case but
+				   it always a valid lump name, not a
+				   command line shortcut like "17". */
+
+extern y_file_name_t Level_file_name;  /* The name of the file in which
+				   the level would be saved. If the
+				   level has been created as the result
+				   of a "c" command, with or without
+				   argument, an empty string. */
+
+extern y_file_name_t Level_file_name_saved;  /* The name of the file in
+				   which the level was last saved. If
+				   the Level has never been saved yet,
+				   an empty string. */
+
+void EmptyLevelData (const char *levelname);
+void update_level_bounds ();
+
+
+#endif	/* DO NOT ADD ANYTHING AFTER THIS LINE */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lists.cc	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,583 @@
+/*
+ *	lists.cc
+ *	Pick an item from a list.
+ *	AYM 1998-08-22
+ */
+
+
+/*
+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 "gfx.h"
+#include "lists.h"
+#include "wadfile.h"
+
+
+// FIXME Move this in a more public place
+void lump_loc_string (char *buf, size_t buf_size, const Lump_loc& lump_loc)
+{
+  if (buf_size < 1)
+    return;
+  int len = buf_size - 1 - (1 + 8 + 1 + 1);  // %08lXh
+  if (len < 1)
+  {
+    *buf = '\0';
+    return;
+  }
+  y_filename (buf, len + 1, lump_loc.wad->pathname ());
+  sprintf (buf + strlen (buf), "(%08lXh)",
+    (unsigned long) lump_loc.ofs & 0xffffffff);
+}
+
+
+/*
+   ask for a name in a given list and call a function (for displaying objects,
+   etc.)
+
+   Arguments:
+      x0, y0  : where to draw the box.
+      prompt  : text to be displayed.
+      listsize: number of elements in the list.
+      list    : list of names (picture names, level names, etc.).
+      listdisp: minimum number of names that should be displayed.
+      name    : what we are editing...
+      width   : \ width and height of an optional window where a picture
+      height  : / can be displayed (used to display textures, sprites, etc.).
+      hookfunc: function that should be called to display a picture.
+		(x1, y1, x2, y2 = coordinates of the window in which the
+		 picture must be drawn, name = name of the picture).
+AYM 1998-02-12 : if hookfunc is <> NULL, a message "Press shift-F1 to save
+  image to file" is displayed and shift-F1 does just that.
+*/
+
+#ifdef DEBUG
+static bool disp_lump_loc = false;
+#endif
+
+void InputNameFromListWithFunc (
+   int x0,
+   int y0,
+   const char *prompt,
+   size_t listsize,
+   const char *const *list,
+   size_t listdisp,
+   char *name,
+   int width,
+   int height,
+   void (*hookfunc)(hookfunc_comm_t *),
+   char flags_to_pass_to_callback)
+{
+const char *msg1 = "Press Shift-F1 to";
+const char *msg2 = "save image to file";
+int    key;
+size_t n;
+size_t win_height;
+int    win_columns;
+int    win_width;
+int    l0;
+int    x1, y1, x2, y2;
+size_t maxlen;
+int    xlist;
+bool   picture_size_drawn = false;
+#ifdef DEBUG
+bool   lump_loc_drawn = false;
+#endif
+bool   ok, firstkey;
+int    entry_out_x0;	/* Edge of name entry widget including border */
+int    entry_out_y0;
+int    entry_out_x1;
+int    entry_out_y1;
+int    entry_text_x0;	/* Edge of text area of name entry widget */
+int    entry_text_y0;
+int    entry_text_x1;
+int    entry_text_y1;
+
+// Sanity
+if (width < 0)
+{
+  nf_bug ("inflwf1");
+  width = 0;
+}
+if (height < 0)
+{
+  nf_bug ("inflwf2");
+  height = 0;
+}
+
+// Compute maxlen, the length of the longest item in the list
+maxlen = 1;
+for (n = 0; n < listsize; n++)
+   if (strlen (list[n]) > maxlen)
+      maxlen = strlen (list[n]);
+for (n = strlen (name) + 1; n <= maxlen; n++)
+   name[n] = '\0';
+char *namedisp = new char[maxlen + 1];
+memset (namedisp, '\xff', maxlen + 1);  // Always != from name
+
+// Compute the minimum width of the dialog box
+l0 = 12;
+if (hookfunc != NULL)
+   {
+   if ((int) (strlen (msg1) + 2) > l0)  // (int) to prevent GCC warning
+      l0 = strlen (msg1) + 2;
+   if ((int) (strlen (msg2) + 2) > l0)  // (int) to prevent GCC warning
+      l0 = strlen (msg2) + 2;
+   }
+xlist = 10 + l0 * FONTW;
+win_columns = l0 + maxlen;
+if ((int) (strlen (prompt)) > win_columns)  // (int) to prevent GCC warning
+   win_columns = strlen (prompt);
+win_width = 10 + FONTW * win_columns;
+x1 = win_width + 8;
+y1 = 10 + 1;
+if (width > 0)
+   win_width += 16 + width;
+// (int) to prevent GCC warning
+win_height = y_max (height + 20, (int) (listdisp * FONTH + 10 + 28));
+if (x0 < 0)
+   x0 = (ScrMaxX - win_width) / 2;
+if (y0 < 0)
+   y0 = (ScrMaxY - win_height) / 2;
+x1 += x0;
+y1 += y0;
+if (x1 + width - 1 < ScrMaxX)
+   x2 = x1 + width - 1;
+else
+   x2 = ScrMaxX;
+if (y1 + height - 1 < ScrMaxY)
+   y2 = y1 + height - 1;
+else
+   y2 = ScrMaxY;
+
+entry_out_x0  = x0 + 10;
+entry_text_x0 = entry_out_x0 + HOLLOW_BORDER + NARROW_HSPACING;
+entry_text_x1 = entry_text_x0 + 10 * FONTW - 1;
+entry_out_x1  = entry_text_x1 + HOLLOW_BORDER + NARROW_HSPACING;
+entry_out_y0  = y0 + 28;
+entry_text_y0 = entry_out_y0 + HOLLOW_BORDER + NARROW_VSPACING;
+entry_text_y1 = entry_text_y0 + FONTH - 1;
+entry_out_y1  = entry_text_y1 + HOLLOW_BORDER + NARROW_VSPACING;
+
+listdisp = y_max (listdisp,
+  (win_height - (entry_out_y0 - y0) - BOX_BORDER - WIDE_VSPACING) / FONTH);
+
+// Draw the dialog box
+DrawScreenBox3D (x0, y0, x0 + win_width, y0 + win_height);
+DrawScreenBoxHollow (entry_out_x0, entry_out_y0, entry_out_x1, entry_out_y1,
+		     BLACK);
+set_colour (WINTITLE);
+DrawScreenText (x0 + 10, y0 + 8, prompt);
+set_colour (WINFG);
+if (hookfunc != NULL)
+   {
+   DrawScreenText (x0 + 10,
+		   y0 + win_height - BOX_BORDER - WIDE_VSPACING - 2 * FONTH,
+		   msg1);
+   DrawScreenText (x0 + 10,
+		   y0 + win_height - BOX_BORDER - WIDE_VSPACING - FONTH,
+		   msg2);
+   }
+if (width > 0)
+   DrawScreenBoxHollow (x1 - 1, y1 - 1, x2 + 1, y2 + 1, BLACK);
+firstkey = true;
+
+// Another way of saying "nothing to rub out"
+int disp_x0 = (x2 + x1) / 2;
+int disp_y0 = (y2 + y1) / 2;
+int disp_x1 = disp_x0 - 1;
+int disp_y1 = disp_y0 - 1;
+
+int maxpatches = 0;
+
+// The event loop
+for (;;)
+   {
+   hookfunc_comm_t c;
+
+   // Reset maxpatches every time when change texture
+   if (strcmp (name, namedisp) != 0)
+     maxpatches = 0;
+
+   // Is "name" in the list ?
+   for (n = 0; n < listsize; n++)
+      if (y_stricmp (name, list[n]) <= 0)
+	 break;
+   ok = n < listsize ? ! y_stricmp (name, list[n]) : false;
+   if (n >= listsize)
+      n = listsize - 1;
+
+   // Display the <listdisp> next items in the list
+   {
+   size_t l;				// Current line
+   int y = entry_out_y0;		// Y-coord of current line
+   int xmin = x0 + xlist;
+   int xmax = xmin + FONTW * maxlen - 1;
+   for (l = 0; l < listdisp && n + l < listsize; l++)
+      {
+      if (false && has_input_event ())	// TEST
+	 {
+	 putchar ('.');		// TEST
+	 fflush (stdout);	// TEST
+	 goto shortcut;		// TEST
+	 }
+      set_colour (WINBG);
+      DrawScreenBox (xmin, y, xmax, y + FONTH - 1);
+      set_colour (WINFG);
+      DrawScreenText (xmin, y, list[n+l]);
+      y += FONTH;
+      }
+   if (l < listdisp)  // Less than <listdisp> names to display
+      {
+      set_colour (WINBG);
+      DrawScreenBox (xmin, y, xmax, entry_out_y0 + listdisp * FONTH - 1);
+      }
+   }
+
+   // Display the entry box and the current text
+   set_colour (BLACK);
+   DrawScreenBox (entry_text_x0, entry_text_y0, entry_text_x1, entry_text_y1);
+   if (ok)  // FIXME this colour scheme should be changed.
+      set_colour (WHITE);
+   else
+      set_colour (WINFG);
+   DrawScreenText (entry_text_x0, entry_text_y0, name);
+
+   // Call the function to display the picture, if any
+   if (hookfunc)
+      {
+      // Display the picture name
+      c.x0         = x1;
+      c.y0         = y1;
+      c.x1         = x2;
+      c.y1         = y2;
+      c.name       = name;
+      c.xofs       = 0;
+      c.yofs       = 0;
+      c.flags      = flags_to_pass_to_callback;
+      const int BAD_VALUE = INT_MAX;
+      c.disp_x0    = BAD_VALUE;  // Catch faulty callbacks
+      c.disp_y0    = BAD_VALUE;  // Catch faulty callbacks
+      c.disp_x1    = BAD_VALUE;  // Catch faulty callbacks
+      c.disp_y1    = BAD_VALUE;  // Catch faulty callbacks
+      c.maxpatches = maxpatches;
+      if (ok)
+	 {
+	 hookfunc (&c);
+	 }
+      else
+	 {
+	 // No picture. Null width & height. Erase everything.
+	 c.disp_x0 = (x2 + x1) / 2;
+	 c.disp_y0 = (y2 + y1) / 2;
+	 c.disp_x1 = c.disp_x0 - 1;
+	 c.disp_y1 = c.disp_y0 - 1;
+	 }
+      strcpy (namedisp, name);
+
+      // Display the (unclipped) size of the picture
+      {
+      const size_t size_chars = 11;
+      const int    size_x0    = x0 + 10;
+      const int    size_y0    = y0 + 50;
+      if (picture_size_drawn)
+	 {
+	 set_colour (WINBG);
+	 DrawScreenBoxwh (size_x0, size_y0, size_chars * FONTW, FONTH);
+	 picture_size_drawn = false;
+	 }
+      if ((c.flags & HOOK_SIZE_VALID) && (c.flags & HOOK_DISP_SIZE))
+	 {
+	 set_colour (WINFG);
+	 char size_buf[100];  // Slack
+	 y_snprintf (size_buf, sizeof size_buf, "%dx%d", c.width, c.height);
+	 if (strlen (size_buf) > size_chars)
+	   strcpy (size_buf + size_chars - 1, ">");
+	 DrawScreenString (size_x0, size_y0, size_buf);
+	 picture_size_drawn = true;
+	 }
+      }
+
+#ifdef DEBUG
+      // Display the file name and file offset of the picture
+      {
+      const size_t loc_chars = win_width / FONTW;
+      const int    loc_x0    = x0;
+      const int    loc_y0    = y0 + win_height;
+      if (lump_loc_drawn)
+	 {
+	 set_colour (WINBG);
+	 DrawScreenBoxwh (loc_x0, loc_y0, loc_chars * FONTW, FONTH);
+	 lump_loc_drawn = false;
+	 }
+      if (disp_lump_loc && (c.flags & HOOK_LOC_VALID))
+	 {
+	 set_colour (WINFG);
+	 char buf[150];  // Slack
+	 lump_loc_string (buf, sizeof buf, c.lump_loc);
+	 DrawScreenString (loc_x0, loc_y0, buf);
+	 lump_loc_drawn = true;
+	 }
+      }
+#endif
+
+      /* If the new picture does not completely obscure the
+	 previous one, rub out the old pixels. */
+      set_colour (BLACK);
+      if (c.disp_x0 == BAD_VALUE
+	|| c.disp_y0 == BAD_VALUE
+	|| c.disp_x1 == BAD_VALUE
+	|| c.disp_y1 == BAD_VALUE)
+	 nf_bug ("Callback %p did not set disp_", hookfunc);
+      else
+	 {
+	 /* +-WINDOW------------------------+   Erase the dots...
+            |                               |
+	    |  +-OLD IMAGE---------------+  |   (this is for the case where
+	    |  | . . : . . . . . . : . . |  |   the image is centred but the
+	    |  |. . .:. . . 3 . . .:. . .|  |   principle is the same if it's
+	    |  | . . : . . . . . . : . . |  |   E.G. in the top left corner)
+	    |  |. . .+-NEW IMAGE---+. . .|  |
+	    |  | . . |             | . . |  |
+	    |  |. 1 .|             |. 2 .|  |
+	    |  | . . |             | . . |  |
+	    |  |. . .+-------------+. . .|  |
+	    |  | . . : . . . . . . : . . |  |
+	    |  |. . .:. . . 4 . . .:. . .|  |
+	    |  | . . : . . . . . . : . . |  |
+	    |  +-------------------------+  |
+	    |                               |
+	    +-------------------------------+ */
+	 if (c.disp_x0 > disp_x0)
+	    DrawScreenBox (disp_x0, disp_y0, c.disp_x0 - 1, disp_y1);  // (1)
+	 if (c.disp_x1 < disp_x1)
+	    DrawScreenBox (c.disp_x1 + 1, disp_y0, disp_x1, disp_y1);  // (2)
+	 if (c.disp_y0 > disp_y0)
+	    DrawScreenBox (y_max (c.disp_x0, disp_x0), disp_y0,
+			   y_min (c.disp_x1, disp_x1), c.disp_y0 - 1); // (3)
+	 if (c.disp_y1 < disp_y1)
+	    DrawScreenBox (y_max (c.disp_x0, disp_x0), c.disp_y1 + 1,
+			   y_min (c.disp_x1, disp_x1), disp_y1);       // (4)
+	 }
+      disp_x0 = c.disp_x0;
+      disp_y0 = c.disp_y0;
+      disp_x1 = c.disp_x1;
+      disp_y1 = c.disp_y1;
+      }
+
+   // Process user input
+shortcut:
+   key = get_key ();
+   if (firstkey && is_ordinary (key) && key != ' ')
+      {
+      for (size_t i = 0; i <= maxlen; i++)
+	 name[i] = '\0';
+      }
+   firstkey = false;
+   size_t len = strlen (name);
+   if (len < maxlen && key >= 'a' && key <= 'z')
+      {
+      name[len] = key + 'A' - 'a';
+      name[len + 1] = '\0';
+      }
+   else if (len < maxlen && is_ordinary (key) && key != ' ')
+      {
+      name[len] = key;
+      name[len + 1] = '\0';
+      }
+   else if (len > 0 && key == YK_BACKSPACE)		// BS
+      name[len - 1] = '\0';
+   else if (key == 21 || key == 23)			// ^U, ^W
+      *name = '\0';
+   else if (key == YK_DOWN)				// [Down]
+      {
+      /* Look for the next item in the list that has a
+	 different name. Why not just use the next item ?
+	 Because sometimes the list has duplicates (for example
+	 when editing a Doom II pwad in Doom mode) and then the
+	 viewer gets "stuck" on the first duplicate. */
+      size_t m = n + 1;
+      while (m < listsize && ! y_stricmp (list[n], list[m]))
+	 m++;
+      if (m < listsize)
+         strcpy (name, list[m]);
+      else
+	 Beep ();
+      }
+   else if (key == YK_UP)				// [Up]
+      {
+      // Same trick as for [Down]
+      int m = n - 1;
+      while (m >= 0 && ! y_stricmp (list[n], list[m]))
+	 m--;
+      if (m >= 0)
+         strcpy (name, list[m]);
+      else
+         Beep ();
+      }
+   else if (key == YK_PD || key == 6 || key == 22)	// [Pgdn], ^F, ^V
+      { 
+      if (n < listsize - listdisp)
+         strcpy (name, list[y_min (n + listdisp, listsize - 1)]);
+      else
+	 Beep ();
+      }
+   else if ((key == YK_PU || key == 2) && n > 0)	// [Pgup], ^B
+      {
+      if (n > listdisp)
+	 strcpy (name, list[n - listdisp]);
+      else
+	 strcpy (name, list[0]);
+      }
+   else if (key == 14)					// ^N
+      {
+      if (n + 1 >= listsize)
+	 {
+	 Beep ();
+         goto done_with_event;
+	 }
+      while (n + 1 < listsize)
+	 {
+	 n++;
+	 if (y_strnicmp (list[n - 1], list[n], 4))
+	    break;
+	 }
+      strcpy (name, list[n]);
+      }
+   else if (key == 16)					// ^P
+      {
+      if (n < 1)
+	 {
+	 Beep ();
+	 goto done_with_event;
+	 }
+      // Put in <n> the index of the first entry of the current
+      // group or, if already at the beginning of the current
+      // group, the first entry of the previous group.
+      if (n > 0)
+	 {
+	 if (y_strnicmp (list[n], list[n - 1], 4))
+	    n--;
+	 while (n > 0 && ! y_strnicmp (list[n], list[n - 1], 4))
+	    n--;
+	 }
+      strcpy (name, list[n]);
+      }
+   else if (key == (YK_CTRL | YK_PD) || key == YK_END)	// [Ctrl][Pgdn], [End]
+      {
+      if (n + 1 >= listsize)
+	 {
+	 Beep ();
+	 goto done_with_event;
+	 }
+      strcpy (name, list[listsize - 1]);
+      }
+   else if (key == (YK_CTRL | YK_PU) || key == YK_HOME)	// [Ctrl][Pgup], [Home]
+      {
+      if (n < 1)
+	 {
+	 Beep ();
+	 goto done_with_event;
+	 }
+      strcpy (name, list[0]);
+      }
+   else if (key == YK_TAB)				// [Tab]
+      strcpy (name, list[n]);
+   else if (key == YK_F1 && c.flags & HOOK_LOC_VALID)	// [F1]: print location
+      {
+      printf ("%.8s: %s(%08lXh)\n",
+	 name, c.lump_loc.wad->pathname (), (unsigned long) c.lump_loc.ofs);
+      }
+   else if (key == YK_F1 + YK_SHIFT	// [Shift][F1] : dump image to file
+    && hookfunc != NULL
+    && (c.flags & HOOK_DRAWN))
+      {
+      const size_t size = strlen (name) + 4 + 1;
+      char *filename = new char[size];
+      al_scpslower (filename, name,   size - 1);
+      al_saps      (filename, ".ppm", size - 1);
+      if (c.img.save (filename) != 0)
+	 {
+	 if (errno == ECHILD)
+	    err ("Error loading PLAYPAL");
+	 else
+	    err ("%s: %s", filename, strerror (errno));
+	 }
+      else
+	 {
+	 printf ("Saved %s as %s\n", name, filename);
+	 }
+      delete[] filename;
+      }
+   else if (key == 1)					// ^A: more patches
+      {
+      if (maxpatches + 1 < c.npatches)
+	maxpatches++;
+      else
+	maxpatches = 0;
+      printf ("maxpatches %d\n", maxpatches);
+      }
+   else if (key == 24)					// ^X: less patches
+      {
+      if (maxpatches == 0)
+	maxpatches = c.npatches - 1;
+      else
+	maxpatches--;
+      printf ("maxpatches %d\n", maxpatches);
+      }
+   else if (ok && key == YK_RETURN)			// [Return]
+      break; /* return "name" */
+   else if (key == YK_ESC)				// [Esc]
+      {
+      name[0] = '\0'; /* return an empty string */
+      break;
+      }
+   else
+      Beep ();
+done_with_event:
+   ;
+   }
+delete[] namedisp;
+}
+
+
+/*
+   ask for a name in a given list
+*/
+
+void InputNameFromList (
+   int x0,
+   int y0,
+   const char *prompt,
+   size_t listsize,
+   const char *const *list,
+   char *name)
+{
+HideMousePointer ();
+InputNameFromListWithFunc (x0, y0, prompt, listsize, list, 5, name, 0, 0, NULL);
+ShowMousePointer ();
+}
+
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lists.h	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,114 @@
+/*
+ *	lists.h
+ *	AYM 2000-04-29
+ */
+
+
+/*
+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.
+*/
+
+
+#ifndef YH_LISTS  /* DO NOT INSERT ANYTHING BEFORE THIS LINE */
+#define YH_LISTS
+
+#include "img.h"
+
+
+/* AYM 19980112
+This is the format of the block that the callback function (*hookfunc)()
+and its caller InputNameFromListWithFunc() use to communicate. It
+includes the old hookfunc parameters (x0, y0, x1, y1, name) plus a
+couple of new parameters. The purpose of those new parameters is :
+  1. Give the caller an easy way to know the actual size of the
+     image (for shift-F1).
+  2. Hence let the caller display the size (remember "yes you
+     can laugh at the way I did it..." ?).
+  3. Provide the caller with various statistics such as number of
+     patches in current texture etc. Good tourist information :)
+  4. Give the caller a way to know whether the image has been
+     drawn (i.e. "ready for shift-F1 ?")
+  5. Give the caller something to call Img::save() on when user
+     presses [Shift][F1].
+Why did I create a structure instead of just adding parameters to the
+hookfunc ? Just for the sake of streamlining the prototype of
+InputNameFromListWithFunc() :)
+In the following,
+- "expected" means "set by caller, read by callee"
+- "returned" means "set by callee, read by caller"
+- "both"     means... both :-)
+
+img
+	The Img is part of the structure. The callee should not
+	make any assumptions regarding the contents and property
+	of img ; it should call resize() and set_opaque()
+	systematically. The callee should not clear the Img
+	before exiting, because the caller may need it for the
+	save-to-file function.
+
+	For that reason, the caller should put the whole image
+	in img, *not* clipped to the dimensions of the screen
+	area on which it will be displayed. Unfortunately, that
+	is currently (2000-10-31) not possible because of
+	limitations in the Sticker class.
+
+	The caller may do whatever it pleases with img.
+*/
+typedef struct
+{
+  int x0;           // [expected] Top left corner of where to draw image
+  int y0;
+  int x1;           // [expected] Bottom right corner
+  int y1;
+  int disp_x0;      // [returned] Top left corner and bottom right corner
+  int disp_y0;      // of area that was drawn on by callee. This is so that
+  int disp_x1;      // the caller knows what needs to be cleared...
+  int disp_y1;
+  int xofs;         // [expected] Top left corner of image in buffer
+  int yofs;
+  const char *name; // [expected] Name of image to display
+  int flags;        // [both]     Flags
+  Img img;          // [returned] Image buffer (clipped !)
+  int width;        // [returned] Width of image before clipping
+  int height;       // [returned] Height of image before clipping
+  int npatches;     // [returned] Textures only : number of patches
+  int maxpatches;   // [expected] Textures: if !0 only render that many patches
+  Lump_loc lump_loc;// [returned] Location of lump that was just displayed
+} hookfunc_comm_t;
+const int HOOK_DRAWN      = 1 << 0;	// Image is completely drawn
+const int HOOK_SIZE_VALID = 1 << 1;	// width and height are valid
+const int HOOK_DISP_SIZE  = 1 << 2;	// Caller should display "widthxheight"
+const int HOOK_SPECTRAL   = 1 << 3;	// Render picture with a spectral look
+const int HOOK_PATCH      = 1 << 4;	// Use patch_dir.loc_by_name()
+const int HOOK_SPRITE     = 1 << 5;	// Use wad_res.sprites.loc_by_name()
+const int HOOK_LOC_VALID  = 1 << 6;	// lump_loc is valid
+const int HOOK_ROOT       = 1 << 7;	// .name is the prefix. Use loc_by_root
+
+
+void InputNameFromListWithFunc (int, int, const char *, size_t,
+  const char *const *, size_t, char *, int, int,
+  void (*hookfunc)(hookfunc_comm_t *),
+  char flags_to_pass_to_callback = 0);
+void InputNameFromList (int, int, const char *, size_t, const char *const *,
+  char *);
+
+
+#endif  /* DO NOT ADD ANYTHING AFTER THIS LINE */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/locate.cc	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,183 @@
+/*
+ *	locate.cc - Locate class
+ *	AYM 2003-03-24
+ */
+
+/*
+This file is copyright André Majorel 2003.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of version 2 of the GNU General Public License as published by the
+Free Software Foundation.
+
+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 <sys/types.h>
+#include <sys/stat.h>
+
+#include "locate.h"
+#include "macro.h"
+#include "trace.h"
+
+
+/*
+ *	Locate::Locate - ctor
+ *
+ *	- search_path points to a NULL-terminated array of C
+ *	  strings (char *) constituting the search path. The
+ *	  paths may contains the following macros, which will be
+ *	  expanded on the fly :
+ *	  %i  the installation directory (DOS only)
+ *	  %v  the version of Yadex
+ *	  ~   $HOME
+ *
+ *	- name is the basename of the file to locate. It may
+ *	  include slashes. If it's absolute, the search path
+ *	  won't be used.
+ *
+ *	- backwards is the direction in which the search path is
+ *	  walked. true is front-to-back, false is back-to-front.
+ */
+Locate::Locate (const char *const *search_path, const char *name, bool backw)
+{
+  this->search_path = search_path;
+  this->name        = name;
+  this->backwards   = backw;
+  absolute          = is_absolute (name);
+  rewound           = true;
+  rewind ();
+}
+
+
+/*
+ *	Locate::rewind - rewind the cursor
+ *
+ *	Calling this method will cause the next call to
+ *	get_next() to return the first match, as if get_next()
+ *	had never been called.
+ */
+void Locate::rewind ()
+{
+  rewound = true;
+
+  if (backwards)
+  {
+    // Advance to the end of the list
+    for (cursor = search_path; *cursor != NULL; cursor++)
+      ;
+  }
+  else
+  {
+    cursor = search_path;
+  }
+}
+
+
+/*
+ *	Locate::get_next - return the next match
+ *
+ *	Returns a pointer to the pathname of the next match, or
+ *	a null pointer if there are no more matches left. The
+ *	returned pointer is valid until get_next() is called
+ *	again or the Locate object is destroyed.
+ */
+const char *Locate::get_next ()
+{
+  if (absolute)
+  {
+    if (! rewound)			// Result has exactly one element
+      return NULL;
+    rewound = false;
+    if (strlen (name) > sizeof pathname - 1)
+    {
+      warn ("%s: file name too long\n", name);
+      return NULL;
+    }
+    strcpy (pathname, name);
+    return pathname;
+  }
+
+  const char *home = getenv ("HOME");
+
+  // Walk the list
+  for (;;)
+  {
+    // Make dirname point to the current path in the search path
+    const char *dirname;
+
+    if (backwards)
+    {
+      if (cursor == search_path)
+	break;
+      cursor--;
+      dirname = *cursor;
+    }
+    else
+    {
+      if (*cursor == NULL)
+	break;
+      dirname = *cursor;
+      cursor++;
+    }
+
+    // Expand the macros in the path into the result buffer
+    int r = macro_expand (pathname, sizeof pathname - 1, dirname,
+      "%i", install_dir,
+      "%v", yadex_version,
+      "~",  home,
+      (const char *) 0);
+    if (r != 0)
+    {
+      trace ("locate", "%s: Could not expand macro #%d", dirname, r);
+      continue;
+    }
+
+    // Append the basename
+    if (strlen (pathname) > 0 && pathname[strlen (pathname)] - 1 != '/')
+    {
+      if (strlen (pathname) + 2 >= sizeof pathname)
+      {
+	warn ("%s: file name too long, skipping\n", dirname);
+	continue;
+      }
+      strcat (pathname, "/");
+    }
+    if (strlen (pathname) + strlen (name) + 1 >= sizeof pathname)
+    {
+      warn ("%s: file name too long, skipping\n", dirname);
+      continue;
+    }
+    strcat (pathname, name);
+
+    // Look for a file of that name.
+    struct stat s;
+    r = stat (pathname, &s);
+    if (r == 0 && ! S_ISDIR (s.st_mode))
+    {
+      trace ("locate", "%s: %s: hit", name, pathname);
+      return pathname;
+    }
+    else if (r == 0 && S_ISDIR (s.st_mode))
+    {
+      errno = EISDIR;
+    }
+    else if (r != 0 && errno != ENOENT)
+    {
+      warn ("%s: %s\n", pathname, strerror (errno));
+    }
+    trace ("locate", "%s: %s: miss (%s)", name, pathname, strerror (errno));
+  }
+
+  return NULL;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/locate.h	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,45 @@
+/*
+ *	locate.h - Locate class
+ *	AYM 2003-03-24
+ */
+
+/*
+This file is copyright André Majorel 2003.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of version 2 of the GNU General Public License as published by the
+Free Software Foundation.
+
+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.
+*/
+
+
+#ifndef YH_LOCATE  /* DO NOT INSERT ANYTHING BEFORE THIS LINE */
+#define YH_LOCATE
+
+
+class Locate
+{
+  public :
+    Locate (const char *const *search_path, const char *name, bool backwards);
+    void rewind ();
+    const char *get_next ();
+
+  private :
+    const char *const *search_path;
+    const char        *name;
+    bool               absolute;
+    bool               backwards;
+    const char *const *cursor;
+    bool               rewound;
+    char               pathname[1025];
+};
+
+
+#endif  /* DO NOT ADD ANYTHING AFTER THIS LINE */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lumpdir.cc	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,281 @@
+/*
+ *	lumpdir.cc
+ *	Lump_dir class
+ *	AYM 1999-11-25
+ */
+
+
+/*
+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 "dependcy.h"
+#include "lumpdir.h"
+#include "wadname.h"
+#include "wadnamec.h"
+#include "wadfile.h"
+
+
+
+/*
+ *	Lump_dir::Lump_dir - ctor 
+ *
+ *	<md> is a pointer to the master directory on which the
+ *	lump directory is based.
+ *	<l> is the first character of the label.
+ *	<sn> is a pointer to the Serial_num of the master
+ *	directory.
+ */
+
+Lump_dir::Lump_dir (MDirPtr *md, char l, Serial_num *sn)
+{
+  have_prev  = false;
+  dependency = new Dependency (sn);
+  master_dir = md;
+  label      = l;
+}
+
+
+/*
+ *	Lump_dir::~Lump_dir - dtor
+ */
+Lump_dir::~Lump_dir ()
+{
+  if (dependency)
+    delete dependency;
+  if (! lump_map.empty ())
+    lump_map.clear ();
+}
+
+
+/*
+ *	Lump_dir::loc_by_name - find a lump by name
+ *
+ *	Return the (wad, offset, length) location of the lump
+ *	named <name>. If not found, set loc.wad to 0.
+ */
+void Lump_dir::loc_by_name (const char *name, Lump_loc& loc)
+{
+  if (dependency->outdated ())
+    refresh ();
+
+  /* Caller asked for same lump twice in a row. Save us a second
+     search. */
+  if (have_prev && ! y_strnicmp (name, name_prev, WAD_NAME))
+  {
+    loc = loc_prev;
+    return;
+  }
+
+  Lump_map::const_iterator i = lump_map.find (name);
+  have_prev = true;
+  if (i == lump_map.end ())
+    loc.wad = loc_prev.wad = 0;
+  else
+    loc = loc_prev = i->second;
+}
+
+
+/*
+ *	Lump_dir::list - return an array of lump names
+ *
+ *	Put a list of all lumps in the list, sorted by name and
+ *	with duplicates removed, in <l>.
+ */
+void Lump_dir::list (Lump_list& l)
+{
+  if (dependency->outdated ())
+    refresh ();
+  l.set (lump_map);
+}
+
+
+/*
+ *	Lump_dir::refresh - update the lump dir. wrt to the master dir.
+ *
+ *	This is called automatically if the master directory has
+ *	changed since the last refresh.
+ */
+void Lump_dir::refresh ()
+{
+  /* refresh() can be called more than once one the same object.
+     And usually is ! */
+  have_prev = false;
+  if (! lump_map.empty ())
+    lump_map.clear ();
+
+  /* Get list of lumps in the master directory. Everything
+     that is between X_START/X_END or XX_START/XX_END and that
+     is not a label is supposed to be added to the Lump_dir. */
+  Wad_name_c x_start  ("%c_START",   label);
+  Wad_name_c x_end    ("%c_END",     label);
+  Wad_name_c xx_start ("%c%c_START", label, label);
+  Wad_name_c xx_end   ("%c%c_END",   label, label);
+  for (MDirPtr dir = *master_dir;
+      dir && (dir = FindMasterDir (dir, x_start.name, xx_start.name));)
+  {
+    MDirPtr start_label = dir;
+    const char *end_label = 0;
+    if (! x_start.cmp (dir->dir.name))
+      end_label = x_end.name;
+    else if (! xx_start.cmp (dir->dir.name))
+      end_label = xx_end.name;
+    else
+      fatal_error ("Bad start label \"%.*s\"", (int) WAD_NAME, dir->dir.name);
+    dir = dir->next;
+    for (;; dir = dir->next)
+    {
+      if (! dir)
+      {
+	warn ("%.128s: no matching %s for %.*s\n",
+	    start_label->wadfile->pathname (),
+	    end_label,
+	    (int) WAD_NAME, start_label->dir.name);
+	break;
+      }
+      // Ended by X_END or, if started by XX_START, XX_END.
+      if (! x_end.cmp (dir->dir.name)
+	|| end_label == xx_end.name && ! xx_end.cmp (dir->dir.name))
+      {
+	if (dir->dir.size != 0)
+	  warn ("%.128s: label %.*s has non-zero size %ld\n",
+	      dir->wadfile->pathname (),
+	      (int) WAD_NAME, dir->dir.name,
+	      (long) dir->dir.size);
+	dir = dir->next;
+	break;
+      } 
+      // Ignore inner labels (X[123]_START, X[123]_END)
+      if (dir->dir.start == 0 || dir->dir.size == 0)
+      {
+	if (! (toupper (dir->dir.name[0]) == label
+	    && (dir->dir.name[1] == '1'
+	     || dir->dir.name[1] == '2'
+	     || dir->dir.name[1] == '3')
+	    && dir->dir.name[2] == '_'
+	    && (! y_strnicmp (dir->dir.name + 3, "START", WAD_NAME - 3)
+		|| ! y_strnicmp (dir->dir.name + 3, "END", WAD_NAME - 3))))
+	  warn ("%.128s: unexpected label \"%.*s\" in %s group\n",
+	      dir->wadfile->pathname (),
+	      (int) WAD_NAME, dir->dir.name,
+	      start_label->dir.name);
+	continue;
+      }
+      wad_flat_name_t name;
+      memcpy (name, dir->dir.name, sizeof name);
+      lump_map[name]
+	= Lump_loc (dir->wadfile, dir->dir.start, dir->dir.size);
+    }
+    if (dir)
+      dir = dir->next;
+  }
+#ifdef DEBUG
+  for (Lump_lumps_map::const_iterator i = lump_map.begin ();
+      i != lump_map.end (); i++)
+  {
+    printf ("%-8.8s %p %08lX %ld\n",
+      i->first._name,
+      i->second.wad,
+      i->second.ofs,
+      i->second.len);
+  }
+#endif
+  dependency->update ();
+}
+
+
+/*-------------------------- Lump_list --------------------------*/
+
+
+Lump_list::Lump_list ()
+{
+  array = 0;
+  nelements = 0;
+}
+
+
+Lump_list::~Lump_list ()
+{
+  clear ();
+}
+
+
+void Lump_list::set (Lump_map& lump_map)
+{
+  clear ();
+  nelements = lump_map.size ();
+  array = new char *[nelements];
+
+  Lump_map::const_iterator i = lump_map.begin ();
+  for (size_t n = 0; n < nelements; n++)
+  {
+    array[n] = new char[WAD_NAME + 1];
+    *array[n] = '\0';
+    strncat (array[n], i++->first.name, WAD_NAME);
+  }
+}
+
+
+void Lump_list::clear ()
+{
+  if (array != 0)
+  {
+    for (size_t n = 0; n < nelements; n++)
+      delete[] array[n];
+    delete[] array;
+  }
+}
+
+
+const char **Lump_list::data ()
+{
+  return (const char **) array;
+}
+
+
+size_t Lump_list::size ()
+{
+  return nelements;
+}
+
+
+/*------------------------- Lump_map_key -------------------------*/
+
+
+//Lump_map_key::Lump_map_key (const char *name)
+//{
+//  memcpy (_name, name, sizeof _name);
+//}
+
+
+/*------------------------ Lump_map_less -------------------------*/
+
+
+bool Lump_map_less::operator ()
+  (const Wad_name& name1, const Wad_name& name2) const
+{
+  return name1.less (name2);
+  //return y_strnicmp ((const char *) &p1, (const char *) &p2, WAD_NAME) < 0;
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lumpdir.h	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,120 @@
+/*
+ *	lumpdir.h
+ *	Lump_dir class
+ *	AYM 2000-04-08
+ */
+
+
+/*
+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.
+*/
+
+
+#ifndef YH_LUMPDIR  /* DO NOT INSERT ANYTHING BEFORE THIS LINE */
+#define YH_LUMPDIR
+
+
+#include <map>
+
+
+class Dependency;
+class Serial_num;
+class Wad_name;
+
+
+/*
+ *	Lump_dir 
+ *	
+ *	The purpose of this class is to hide the details of how
+ *	lumps are stored in the wads from Yadex. It provides
+ *	two basic services :
+ *
+ *	- loc_by_name()	Return the lump location (WadPtr,
+ *			offset, length) of a lump by name. If
+ *			lump does not exist, returns a NULL
+ *			WadPtr.
+ *
+ *	- list()	Return a Lump_list object that provides
+ *			what InputNameFromListWithFunc() needs
+ *			to browse the patches. I suggest that
+ *			this object be created immediately
+ *			before it's needed and destroyed
+ *			immediately after because it is not
+ *			intended to remain valid across calls to
+ *			refresh(). Ignoring this advice will
+ *			cause some interesting crashes.
+ */
+
+// The key of the map is the lump name
+struct Lump_map_key
+{
+  Lump_map_key (const char *name);
+  wad_name_t _name;
+};
+
+// How to compare two keys
+struct Lump_map_less
+{
+  //bool operator() (const Lump_map_key& p1, const Lump_map_key& p2) const;
+  bool operator() (const Wad_name& p1, const Wad_name& p2) const;
+};
+
+typedef std::map<Wad_name, Lump_loc, Lump_map_less> Lump_map;
+
+class Lump_list
+{
+  public :
+    Lump_list ();
+    ~Lump_list ();
+    const char **data ();
+    size_t size ();
+    void set (Lump_map& lump_map);
+    void clear ();
+
+  private :
+    char **array;
+    size_t nelements;
+};
+
+class Lump_dir
+{
+  public :
+    Lump_dir (MDirPtr *md, char l, Serial_num *sn);
+    ~Lump_dir ();
+    void loc_by_name (const char *name, Lump_loc& loc);
+    void list (Lump_list& l);
+
+  protected :
+    void refresh ();
+
+    Dependency *dependency;		// Resource on which we depend
+    MDirPtr    *master_dir;
+    char       label;			// First character of label
+    Lump_map   lump_map;		// List of lumps, sorted by name
+					// (no duplicates), with their
+					// location.
+    bool       have_prev;
+    Lump_loc   loc_prev;
+    wad_name_t name_prev;
+};
+
+
+#endif  /* DO NOT ADD ANYTHING AFTER THIS LINE */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/macro.cc	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,264 @@
+/*
+ *	macro.cc
+ *	Expanding macros
+ *	AYM 1999-11-30
+ */
+
+
+/*
+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 "macro.h"
+
+
+/*
+ *	macro_expand, vmacro_expand - expand macro references in a string
+ *
+ *	Copies the NUL-terminated string in <fmt> into the
+ *	buffer <buf>, replacing certain strings by other
+ *	strings. <buf> must be at least (<size> + 1) characters
+ *	long.
+ *
+ *	The macro definitions are provided by the optional
+ *	arguments that follow <fmt>. You must pass two (const
+ *	char *) for each macro. The first is the name of the
+ *	macro, NUL-terminated. The second is the value of the
+ *	macro, also NUL-terminated. The last macro value must be
+ *	followed by a null pointer ((const char *) 0).
+ *
+ *	Matching is case-sensitive. The first match is used.
+ *	For example,
+ *
+ *	  macro_expand (buf, 99, "a%bcd", "%b", "1", "%bc", "2", (char *) 0);
+ *
+ *	puts "a1cd" in buf.
+ *
+ *	If the value of a macro to expand is a null pointer, the
+ *	macro expands to an empty string.
+ *
+ *	If <fmt> expands to more than <size> characters, only
+ *	the first <size> characters of the expansion are stored
+ *	in <buf>. After the function returns, <buf> is
+ *	guaranteed to be NUL-terminated.
+ *
+ *	Return 0 if successful, non-zero if one of the macros
+ *	could not be expanded (value was a null pointer). In
+ *	that case, the actual number returned is the number of
+ *	the first macro that could not be expanded, starting
+ *	from 1.
+ */
+int macro_expand (char *buf, size_t size, const char *fmt, ...)
+{
+  va_list list;
+  va_start (list, fmt);
+  return vmacro_expand (buf, size, fmt, list);
+}
+
+
+int vmacro_expand (char *buf, size_t size, const char *fmt, va_list list)
+{
+  int rc = 0;
+  int macro_no = 0;
+
+  *buf = '\0';
+  // This is awful, but who cares ?
+  while (*fmt)
+  {
+    va_list l;
+    const char *macro_name = 0;
+    const char *macro_value = 0;
+
+#ifdef __va_copy
+    __va_copy(l, list);
+#else
+    l = list;
+#endif
+
+    while (macro_name = va_arg (l, const char *))
+    {
+      macro_value = va_arg (l, const char *);
+      size_t len1 = strlen (fmt);
+      size_t len2 = strlen (macro_name);
+      if (len1 >= len2 && ! memcmp (fmt, macro_name, len2))
+	break;
+    }
+    if (macro_name != 0)
+    {
+      macro_no++;
+      if (macro_value == 0)
+      {
+	if (rc == 0)
+	  rc = macro_no;
+      }
+      else
+        al_saps (buf, macro_value, size);
+      fmt += strlen (macro_name);
+    }
+    else
+    {
+      al_sapc (buf, *fmt, size);
+      fmt++;
+    }
+  }
+  return rc;
+}
+
+
+/*
+ *	macro_expand - expand macro references in a string
+ *
+ *	Copies the NUL-terminated string in <fmt> into the
+ *	buffer <buf>, replacing certain strings by other
+ *	strings. <buf> must be at least (<size> + 1) characters
+ *	long.
+ *
+ *	The macro definitions are obtained by scanning the
+ *	iterator range <macdef_begin> through <macdef_end>. The
+ *	only constraints on these iterators are that they must
+ *	be input iterators and iterator->name and
+ *	iterator->value must be defined and point to
+ *	NUL-terminated strings.
+ *
+ *	Matching is case-sensitive. If several names would
+ *	match, the first one is used.  For example,
+ *
+ *	  struct macdef
+ *	  {
+ *	    const char *name;
+ *	    const char *value;
+ *	    macdef (const char *name, const char *value) :
+ *	      name (name), value (value);
+ *	  };
+ *	  std::list<macdef> macdefs;
+ *	  macdefs.push_back (macdef ("%b", "1"));
+ *	  macdefs.push_back (macdef ("%bc", "2"));
+ *	  macro_expand (buf, 99, "a%bcd", macdefs.begin (), macdefs.end ());
+ *
+ *	puts "a1cd" in buf, not "a2d".
+ *
+ *	If the value of a macro to expand is a null pointer, the
+ *	macro expands to an empty string.
+ *
+ *	If <fmt> expands to more than <size> characters, only
+ *	the first <size> characters of the expansion are stored
+ *	in <buf>. After the function returns, <buf> is
+ *	guaranteed to be NUL-terminated.
+ *
+ *	Return 0 if successful, non-zero if one of the macros
+ *	could not be expanded (value was a null pointer). In
+ *	that case, the actual number returned is the number of
+ *	the first macro that could not be expanded, starting
+ *	from 1.
+ */
+template <typename const_iterator>
+int macro_expand (char *buf, size_t size, const char *fmt,
+  const_iterator macdef_begin, const_iterator macdef_end)
+{
+  int rc = 0;
+  int macro_no = 0;
+
+  *buf = '\0';
+  size_t fmt_len = strlen (fmt);
+  while (*fmt != '\0')
+  {
+    const char *macro_name     = 0;
+    const char *macro_value    = 0;
+    size_t      macro_name_len = 0;
+    bool        match          = false;
+    for (const_iterator i = macdef_begin; i != macdef_end; ++i)
+    {
+      macro_name     = i->name;
+      macro_value    = i->value;
+      macro_name_len = strlen (macro_name);
+      if (macro_name_len <= fmt_len
+	  && memcmp (fmt, macro_name, macro_name_len) == 0)
+      {
+	match = true;
+	break;
+      }
+    }
+    if (match)
+    {
+      macro_no++;
+      if (macro_value == 0)
+      {
+	if (rc == 0)
+	  rc = macro_no;
+      }
+      else
+        al_saps (buf, macro_value, size);
+      fmt     += macro_name_len;
+      fmt_len -= macro_name_len;
+    }
+    else
+    {
+      al_sapc (buf, *fmt, size);
+      fmt++;
+      fmt_len--;
+    }
+  }
+  return rc;
+}
+
+
+#ifdef TEST
+/*
+  make CXXFLAGS='-DTEST -DY_UNIX -DY_X11'
+    LDFLAGS=../obj/0/atclib/al_saps.o\ ../obj/0/atclib/al_sapc.o
+    macro
+*/
+
+#include <list>
+#include <algorithm>
+
+
+struct macdef
+{
+  const char *name;
+  const char *value;
+  macdef (const char *name, const char *value) :
+    name (name), value (value) { }
+};
+
+
+void dump (const macdef& m)
+{
+  fprintf (stderr, "%s=%s\n", m.name, m.value);
+}
+
+
+int main ()
+{
+  char buf[100];
+  std::list<macdef> macdefs;
+  macdefs.push_back (macdef ("%b", "1"));
+  macdefs.push_back (macdef ("%bc", "2"));
+  std::for_each (macdefs.begin (), macdefs.end (), dump);
+  macro_expand (buf, sizeof buf - 1, "a%bcd", macdefs.begin (), macdefs.end ());
+  puts (buf);
+  return 0;
+}
+
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/macro.h	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,42 @@
+/*
+ *	macro.h
+ *	Expanding macros
+ *	AYM 1999-11-30
+ */
+
+
+/*
+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.
+*/
+
+
+typedef struct
+{
+  const char *name;
+  const char *value;
+} macdef_t;
+
+
+int macro_expand (char *buf, size_t size, const char *fmt, ...);
+int macro_expand (char *buf, size_t size, const char *fmt, const macdef_t *def);
+int vmacro_expand (char *buf, size_t size, const char *fmt, va_list list);
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/masterdir.h	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,21 @@
+/*
+ *	masterdir.h
+ *	Master_dir class
+ *	AYM 2000-04-06
+ */
+
+
+#ifndef YH_MASTERDIR  /* DO NOT INSERT ANYTHING BEFORE THIS LINE */
+#define YH_MASTERDIR
+
+
+class Master_dir
+{
+  public :
+    Master_dir ();
+  private :
+    Serial_num serial;
+};
+
+
+#endif  /* DO NOT ADD ANYTHING AFTER THIS LINE */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/memory.cc	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,181 @@
+/*
+ *	memory.cc
+ *	Memory allocation routines.
+ *	BW & RQ sometime in 1993 or 1994.
+ */
+
+
+/*
+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"
+
+/*
+   Note from RQ:
+      To prevent memory fragmentation on large blocks (greater than 1K),
+      the size of all blocks is rounded up to 8K.  Thus, "realloc" will
+      move the block if and only if it has grown or shrunk enough to
+      cross a 8K boundary.
+      I don't do that for smaller blocks (smaller than 1K), because this
+      would waste too much space if these blocks were rounded up to 8K.
+      There are lots of "malloc"'s for very small strings (9 characters)
+      or filenames, etc.
+      Thanks to Craig Smith (bcs@cs.tamu.edu) for some of his ideas
+      about memory fragmentation.
+*/
+
+#define SIZE_THRESHOLD	1024
+#define SIZE_OF_BLOCK	4095  /* actually, this is (size - 1) */
+
+
+/*
+   allocate memory with error checking
+*/
+
+void *GetMemory (unsigned long size)
+{
+void *ret;
+
+/* On 16-bit systems (BC 4.0), size_t is only 16-bit long so
+   you can't malloc() more than 64 kB at a time. Catch it. */
+if (size != (size_t) size)
+   fatal_error ("GetMemory: %lu B is too much for this poor machine.", size);
+
+/* limit fragmentation on large blocks */
+if (size >= SIZE_THRESHOLD)
+   size = (size + SIZE_OF_BLOCK) & ~SIZE_OF_BLOCK;
+ret = malloc ((size_t) size);
+if (!ret)
+   {
+   /* retry after having freed some memory, if possible */
+   FreeSomeMemory ();
+   ret = malloc ((size_t) size);
+   }
+if (!ret)
+   fatal_error ("out of memory (cannot allocate %u bytes)", size);
+return ret;
+}
+
+
+/*
+   reallocate memory with error checking
+*/
+
+void *ResizeMemory (void *old, unsigned long size)
+{
+void *ret;
+
+/* On 16-bit systems (BC 4.0), size_t is only 16-bit long so
+   you can't malloc() more than 64 kB at a time. Catch it. */
+if (size != (size_t) size)
+   fatal_error ("ResizeMemory: %lu B is too much for this poor machine.", size);
+
+/* limit fragmentation on large blocks */
+if (size >= SIZE_THRESHOLD)
+   size = (size + SIZE_OF_BLOCK) & ~SIZE_OF_BLOCK;
+ret = realloc (old, (size_t) size);
+if (!ret)
+   {
+   FreeSomeMemory ();
+   ret = realloc (old, (size_t) size);
+   }
+if (!ret)
+   fatal_error ("out of memory (cannot reallocate %lu bytes)", size);
+return ret;
+}
+
+
+/*
+   free memory
+*/
+
+void FreeMemory (void *ptr)
+{
+/* just a wrapper around free(), but provide an entry point */
+/* for memory debugging routines... */
+free (ptr);
+}
+
+
+/*
+   allocate memory from the far heap with error checking
+*/
+
+void huge *GetFarMemory (unsigned long size)
+{
+void huge *ret;
+
+/* limit fragmentation on large blocks */
+if (size >= SIZE_THRESHOLD)
+   size = (size +  SIZE_OF_BLOCK) & ~SIZE_OF_BLOCK;
+ret = farmalloc (size);
+if (!ret)
+   {
+   /* retry after having freed some memory, if possible */
+   FreeSomeMemory ();
+   ret = farmalloc (size);
+   }
+if (!ret)
+   fatal_error ("out of memory (cannot allocate %lu far bytes)", size);
+return ret;
+}
+
+
+
+/*
+   reallocate memory from the far heap with error checking
+*/
+
+void huge *ResizeFarMemory (void huge *old, unsigned long size)
+{
+void huge *ret;
+
+/* limit fragmentation on large blocks */
+if (size >= SIZE_THRESHOLD)
+   size = (size + SIZE_OF_BLOCK) & ~SIZE_OF_BLOCK;
+ret = farrealloc (old, size);
+if (!ret)
+   {
+   FreeSomeMemory ();
+   ret = farrealloc (old, size);
+   }
+if (!ret)
+   fatal_error ("out of memory (cannot reallocate %lu far bytes)", size);
+return ret;
+}
+
+
+
+/*
+   free memory from the far heap
+*/
+
+void FreeFarMemory (void huge *ptr)
+{
+/* just a wrapper around farfree(), but provide an entry point */
+/* for memory debugging routines... */
+farfree (ptr);
+}
+
+
+/* end of file */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/menu.cc	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,1271 @@
+/*
+ *	menu.cc
+ *	AYM 1998-12-01
+ */
+
+
+/*
+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.
+*/
+
+
+/*
+These are the pop-up and pull-down menus.
+
+Events that are not understood (E.G. [Left] and [Right])
+are put back in the input buffer before the
+function returns.
+*/
+
+
+#include "yadex.h"
+#include "events.h"
+#include "gfx.h"
+#include "menu.h"
+#include "menudata.h"
+
+
+extern const char *MI_SEPARATION = "";
+
+const unsigned char MIF_MACTIVE = 0x03;
+const unsigned char MIF_MTICK = 0x0c;
+const unsigned char MIF_SEPAR = 0x10;
+
+const short VSPACE = 2;				// Pixels between items
+
+
+/* 
+ *	Menu_item - a menu item class
+ */
+class Menu_item
+{
+  public :
+    Menu_item ()
+    {
+      flags          = MIF_NTICK | MIF_NACTIVE;
+      tilde_key      = YK_;
+      shortcut_key   = YK_;
+      str            = 0;
+    }
+
+    unsigned char flags;	// Logical-or of MIF_?ACTIVE MIF_?TICK MIF_SEPAR
+    inpev_t       tilde_key;
+    inpev_t       shortcut_key;
+    short         y;		// Top of item, relative to ly0. If there is a
+				// separation, it is above y.
+    const char    *str;
+    union
+    {
+      bool s;			// Static
+      bool *v;			// Pointer to variable
+      struct
+      {
+	micb_t f;		// Pointer to callback function
+	micbarg_t a;		// Argument
+      } f;
+    }
+    tick;
+    union
+    {
+      bool s;			// Static
+      bool *v;			// Pointer to variable
+      struct
+      {
+	micb_t f;		// Pointer to callback function
+	micbarg_t a;		// Argument
+      } f;
+    }
+    active;
+};
+
+
+/*
+ *	Menu_priv - Menu's private data
+ */
+class Menu_priv
+{
+  public :
+
+    Menu_priv ()
+    {
+      flags         = 0;
+      title         = 0;
+      title_len     = 0;
+      items_ks_len  = 0;
+      items_len     = 0;
+      items.clear ();
+      user_ox0      = -1;
+      user_oy0      = -1;
+      ox0           = -1;
+      oy0           = -1;
+      need_geom     = true;
+      visible       = false;
+      visible_disp  = false;
+      line          = 0;
+      line_disp     = UINT_MAX;
+      item_height   = FONTH + VSPACE;
+    }
+
+    void vinit (Menu& m, const char *title, va_list argp);
+    void cook ();
+    void draw ();
+    void draw_one_line (size_t line, bool highlighted);
+    void geom ();
+    int process_event (const input_status_t *is);
+
+    // Menu data
+    unsigned char flags;	// MF_MENUDATA
+				//          The strings come from a Menu_data.
+				// MF_POPUP Used as popup (not pull-down) menu
+				//          If set, the title is shown and
+				//          button releases are treated
+				//          differently.
+				// MF_TICK  At least one item can be ticked
+				//          (has the MIF_[SVF]TICK flag).
+				// MF_SHORTCUT  At least one item has a key
+				//          shortcut key.
+				// MF_NUMS  Force the use of standard
+				//          shortcuts [0-9a-zA-Z] even if
+				//          index/key shortcuts exist.
+    const char *title;		// NULL if no title
+    size_t     title_len;	// Length of <title> (or 0 if none)
+    size_t     items_ks_len;	// Length of the longest item counting key sc.
+    size_t     items_len;	// Length of the longest item not counting k.s.
+    const Menu_data *menudata;
+    std::vector<Menu_item> items;
+
+    // Geometry as the user would like it to be
+    int    user_ox0;		// Top left corner. < 0 means centered.
+    int    user_oy0;		// Top left corner. < 0 means centered.
+
+    // Geometry as it should be
+    int    ix0, iy0, ix1, iy1;	// Corners of inner edge of window
+    int    ox0, oy0, ox1, oy1;	// Corners of outer edge of window
+    int    width;		// Overall width of window
+    int    height;		// Overall height of window
+    int    ty0;			// Y-pos of title
+    int    ly0;			// Y-pos of first item
+
+    // Geometry as it is displayed
+    int    ox0_disp;
+    int    oy0_disp;
+    int    width_disp;
+    int    height_disp;
+
+    // Status
+    bool   need_geom;		// Need to call geom() again
+    bool   visible;		// Should the menu be visible ?
+    bool   visible_disp;	// Is it really visible ?
+    size_t line;		// Which line should be highlighted ?
+    size_t line_disp;		// Which line is actually highlighted ?
+    inpev_t _last_shortcut_key;	// Shortcut key for last selected item.
+
+    // Misc
+    unsigned short item_height;
+};
+
+
+/* First subscript :  0 = normal, 1 = greyed out
+   Second subscript : 0 = normal, 1 = highlighted */
+const colour_pair_t menu_colour[2][2] =
+{
+  {
+    { WINBG,    WINFG        },    // Normal entry
+    { WINBG_HL, WINFG_HL     }     // Normal entry, highlighted
+  },
+  {
+    { WINBG,    WINFG_DIM    },    // Greyed out entry
+    { WINBG_HL, WINFG_DIM_HL }     // Greyed out entry, highlighted
+  }
+};
+
+const unsigned char MF_POPUP    = 0x01;
+const unsigned char MF_TICK     = 0x02;
+const unsigned char MF_TILDE    = 0x04;
+const unsigned char MF_SHORTCUT = 0x08;
+const unsigned char MF_NUMS     = 0x10;
+const unsigned char MF_MENUDATA = 0x20;
+
+
+/*
+ *	Menu::Menu - ctor from arguments in variable number
+ *
+ *	Another ctor for Menu, suited to the creation of pull
+ *	down menus.
+ *
+ *	Expects the title of the menu followed by repeats of
+ *	either of the following sets of arguments, in any order :
+ *
+ *	1) Menu item
+ *
+ *	  A menu item is made of 3 or more arguments :
+ *
+ *	    const char *
+ *			A NUL-terminated string that will be
+ *			used to display the item. The first
+ *			occurrence of a tilde ("~") in the
+ *			string indicates that the following
+ *			character will be used as a local
+ *			shortcut for this item.
+ *
+ *			That string must remain valid and should
+ *			not change during the lifetime of the
+ *			Menu object.
+ *
+ *	    inpev_t	The global shortcut key associated to
+ *			this item. That key will be displayed on
+ *			the right of the menu.
+ *
+ *	    <option> ...
+ *			Zero or more options.
+ *
+ *	    (unsigned char) 0
+ *			The end of the item.
+ *
+ *	  Where <option> is any of the following pairs of
+ *	  arguments :
+ *
+ *	    (unsigned char) MIF_STICK
+ *	    bool ticked
+ *			Indicates that this item can be ticked.
+ *			If <ticked> is true, the item will be
+ *			initially ticked. To change the state of
+ *			the item, call set_ticked().
+ *
+ *	    (unsigned char) MIF_VTICK
+ *	    bool *ticked
+ *			Indicates that this item can be ticked.
+ *			The argument is a pointer to a boolean
+ *			variable. Whenever this item is
+ *			displayed, the variable is read and the
+ *			item is shown as ticked or unticked
+ *			depending on whether the function
+ *			returned true or false.
+ *
+ *	    (unsigned char) MIF_FTICK
+ *	    boolcb_t ticked
+ *	    void *arg
+ *			Indicates that this item can be ticked.
+ *			The argument is a pointer to a function
+ *			taking only one argument (<arg>) and
+ *			returning bool.  Whenever this item is
+ *			displayed, the function is called and
+ *			the item is shown as ticked or unticked
+ *			depending on whether the function
+ *			returned true or false.
+ *
+ *	    (unsigned char) MIF_SACTIVE
+ *	    bool active
+ *			Indicates that this item can be greyed
+ *			out. If <active> is false the item
+ *			will be initially greyed out. To change
+ *			the state of the item, call
+ *			set_active().
+ *
+ *	    (unsigned char) MIF_VACTIVE
+ *	    bool *active
+ *			Indicates that this item can be greyed
+ *			out. The argument is a pointer to a
+ *			boolean variable. Whenever this item is
+ *			displayed, the variable is read and the
+ *			item is shown as greyed out or not
+ *			depending on whether the function
+ *			returned false or true.
+ *
+ *	    (unsigned char) MIF_FACTIVE
+ *	    boolcb_t active
+ *			Indicates that this item can be greyed
+ *			out. The argument is a pointer to a
+ *			function taking only one argument
+ *			(<arg>) and returning bool. Whenever
+ *			this item is displayed, the function is
+ *			called and the item is shown as greyed
+ *			out or not depending on whether the
+ *			function returned false or true.
+ *
+ *	2) Separation
+ *
+ *	  A separation is made of exactly 1 argument :
+ *
+ *	    (const char *) MI_SEPARATION
+ *
+ *	Pass a NULL pointer after the last group of arguments.
+ *
+ *	For a given item, the options MIF_STICK, MIF_VTICK and
+ *	MIF_FTICK are mutually exclusive. For a given item, the
+ *	options MIF_SACTIVE, MIF_VACTIVE and MIF_FACTIVE are
+ *	mutually exclusive.
+ *
+ *	A MI_SEPARATION argument at the end of the list (i.e.
+ *	not followed by an item) is ignored.
+ *
+ *	The ticked and greyed out states can change at any time
+ *	but will not be reflected until the menu is redrawn from
+ *	scratch.
+ */
+Menu::Menu (const char *title, ...)
+{
+  priv = new Menu_priv;
+  va_list argp;
+  va_start (argp, title);
+  priv->vinit (*this, title, argp);
+  va_end (argp);
+  priv->cook ();
+}
+
+
+/*
+ *	Menu::Menu - ctor from an argument list
+ *
+ *	This is the same thing as Menu::Menu (const char
+ *	*title, ...) except that it expects a pointer on the
+ *	list of arguments.
+ */
+Menu::Menu (const char *title, va_list argp)
+{
+  priv = new Menu_priv;
+  priv->vinit (*this, title, argp);
+  priv->cook ();
+}
+
+
+/*
+ *	Menu::Menu - ctor from a list
+ *
+ *	Another ctor for Menu, suited to the creation of the
+ *	menu from a list.
+ */
+Menu::Menu (
+   const char   *title,
+   al_llist_t   *list,
+   const char   *(*getstr) (void *))
+{
+  priv = new Menu_priv;
+  set_title (title);
+  size_t nitems = y_min (al_lcount (list), 100);
+  priv->items.resize (nitems);
+  size_t line;
+  for (al_lrewind (list), line = 0;
+       ! al_leol (list) && line < nitems;
+       al_lstep (list), line++)
+    priv->items[line].str = getstr (al_lptr (list));
+  priv->cook ();
+}
+
+
+/*
+ *	Menu::Menu - ctor from a Menu_data
+ */
+Menu::Menu (const char *title, const Menu_data& menudata)
+{
+  priv = new Menu_priv;
+  priv->menudata = &menudata;
+  priv->flags |= MF_MENUDATA;
+  set_title (title);
+  size_t nitems = menudata.nitems ();
+  priv->items.resize (nitems);
+  priv->cook ();
+}
+
+
+/*
+ *	Menu::~Menu - dtor
+ */
+Menu::~Menu ()
+{
+  delete priv;
+}
+
+
+/*
+ *	Menu_priv::vinit - initialize the menu from an argument list
+ */
+void Menu_priv::vinit (Menu& m, const char *title, va_list argp)
+{
+  bool tick = false;
+
+  m.set_title (title);
+
+  while (items.size () < 100)
+  {
+    Menu_item i;
+
+    const char *str = va_arg (argp, const char *);
+    while (str == MI_SEPARATION)
+    {
+      i.flags |= MIF_SEPAR;
+      str = va_arg (argp, const char *);
+    }
+    if (str == 0)
+      break;
+
+    i.str            = str;
+    i.shortcut_key   = (inpev_t) va_arg (argp, int);
+    unsigned char flag;
+    while ((flag = (unsigned char) va_arg (argp, int)) != 0)
+    {
+      if (flag == MIF_SACTIVE)
+      {
+	i.flags  = (i.flags & ~MIF_MACTIVE) | MIF_SACTIVE;
+	i.active.s = (bool) va_arg (argp, int);
+      }
+      else if (flag == MIF_VACTIVE)
+      {
+	i.flags  = (i.flags & ~MIF_MACTIVE) | MIF_VACTIVE;
+	i.active.v = va_arg (argp, bool *);
+      }
+      else if (flag == MIF_FACTIVE)
+      {
+	i.flags  = (i.flags & ~MIF_MACTIVE) | MIF_FACTIVE;
+	i.active.f.f = va_arg (argp, micb_t);
+	i.active.f.a = va_arg (argp, micbarg_t);
+      }
+      else if (flag == MIF_STICK)
+      {
+	tick = true;
+	i.flags  = (i.flags & ~MIF_MTICK) | MIF_STICK;
+	i.tick.s = (bool) va_arg (argp, int);
+      }
+      else if (flag == MIF_VTICK)
+      {
+	tick = true;
+	i.flags  = (i.flags & ~MIF_MTICK) | MIF_VTICK;
+	i.tick.v = va_arg (argp, bool *);
+      }
+      else if (flag == MIF_FTICK)
+      {
+	tick = true;
+	i.flags  = (i.flags & ~MIF_MTICK) | MIF_FTICK;
+	i.tick.f.f = va_arg (argp, micb_t);
+	i.tick.f.a = va_arg (argp, micbarg_t);
+      }
+      else if (flag != 0)
+      {
+	nf_bug ("Menu::ctor: flag %d", (int) flag);
+      }
+    }
+    items.push_back (i);
+  }
+
+  if (tick)
+    flags |= MF_TICK;
+}
+
+
+/*
+ *	Menu_priv::cook - parse the menu item strings
+ *
+ *	Compute items_len, items_ks_len and prepare the cooked
+ *	tilde shortcuts.
+ */
+void Menu_priv::cook ()
+{
+  items_len    = 0;
+  items_ks_len = 0;
+  short y      = 0;
+
+  for (size_t line = 0; line < items.size (); line++)
+  {
+    Menu_item& i = items[line];
+    if (i.shortcut_key != YK_)
+      flags |= MF_SHORTCUT;
+    if ((i.flags & MIF_MTICK) != MIF_NTICK)
+      flags |= MF_TICK;
+    if (i.flags & MIF_SEPAR)
+      y += 2 * (NARROW_VSPACING + NARROW_BORDER);
+    i.y = y;
+    y += item_height;
+    size_t len = 0;
+    i.tilde_key = YK_;
+    const char *str = (flags & MF_MENUDATA) ? (*menudata)[line] : i.str;
+    for (const char *p = str; *p != '\0'; p++)
+      if (p[0] == '~' && p[1] != '\0' && i.tilde_key == YK_)
+      {
+	i.tilde_key = tolower (p[1]);
+	flags |= MF_TILDE;
+      }
+      else
+	len++;
+    size_t len_ks = len;
+    if (i.shortcut_key != YK_)
+      len_ks += strlen (key_to_string (i.shortcut_key)) + 2;
+    if (len > items_len)
+      items_len = len;
+    if (len_ks > items_ks_len)
+      items_ks_len = len_ks;
+  }
+
+  if (flags & MF_TICK)
+  {
+    items_len    += 2;		// Tick mark
+    items_ks_len += 2;
+  }
+  if (flags & MF_SHORTCUT)
+  {
+    items_len    += 4;		// Space between strings and shortcut
+    items_ks_len += 4;
+  }
+  if (! (flags & MF_TILDE) && ! (flags & MF_SHORTCUT))
+    flags |= MF_NUMS;
+  if (flags & MF_NUMS)
+  {
+    items_len    += 4;		// [1-9a-zA-Z] prefix
+    items_ks_len += 4;
+  }
+}
+
+
+/*
+ *	Menu::set_title - set the title
+ *
+ *	Set the title of the menu (it's ignored unless the menu
+ *	is set in popup mode).
+ *
+ *	Bug: changing the title does not take effect until the
+ *	next display from scratch.
+ */
+void Menu::set_title (const char *title)
+{
+  priv->title = title;
+  size_t title_len = title ? strlen (title) : 0;
+
+  /* If the length of the title has changed,
+     force geom() to be called again. */
+  if (title_len != priv->title_len)
+    priv->need_geom = true;
+
+  priv->title_len = title_len;
+}
+
+
+/*
+ *	Menu::set_coords - position or reposition the menu window.
+ *
+ *	(<x0>,<y0>) is the top left corner.
+ *	If <x0> is < 0, the window is horizontally centred.
+ *	If <y0> is < 0, the window is vertically centred.
+ */
+void Menu::set_coords (int x0, int y0)
+{
+  if (x0 != priv->ox0 || y0 != priv->oy0)
+    priv->need_geom = true;  // Force geom() to be called
+
+  priv->user_ox0 = x0;
+  priv->user_oy0 = y0;
+}
+
+
+/*
+ *	Menu::set_item_no - set the current line
+ *
+ *	The current line number is set to <item_no>. The first
+ *	line bears number 0.
+ */
+void Menu::set_item_no (int item_no)
+{
+  priv->line = item_no;
+}
+
+
+/*
+ *	Menu::set_popup - set the popup flag
+ *
+ *	If <popup> is true, the popup flag is set. If <popup> is
+ *	false, the popup flag is cleared.
+ */
+void Menu::set_popup (bool popup)
+{
+  if (popup != !! (priv->flags & MF_POPUP))
+    priv->need_geom = true;  // Force geom() to be called
+  if (popup)
+    priv->flags |= MF_POPUP;
+  else
+    priv->flags &= ~MF_POPUP;
+}
+
+
+/*
+ *	Menu::set_force_numbers - set the force_numbers flags
+ *
+ *	If <force_numbers> is true, the force_numbers flag is
+ *	set. If <force_numbers> is false, the force_numbers flag
+ *	is cleared.
+ *
+ *	The effect of the <force_numbers> flag is to disable key
+ *	shortcuts and tilde shortcuts and to add automatic
+ *	numbering of items ([1-9a-zA-Z]).
+ *
+ *	If none of the items has a tilde or key shortcut,
+ *	<force_numbers> is automatically set. Otherwise, is it
+ *	off by default.
+ */
+void Menu::set_force_numbers (bool force_numbers)
+{
+  if (force_numbers != !! (priv->flags & MF_NUMS))
+    priv->need_geom = true;  // Force geom() to be called.
+  if (force_numbers)
+    priv->flags |= MF_NUMS;
+  else
+    priv->flags &= ~MF_NUMS;
+}
+
+
+/*
+ *	Menu::set_visible - set the visible flag
+ *
+ *	If <visible> is true, the visible flag is set. If
+ *	<visible> is false, the visible flag is cleared.
+ */
+void Menu::set_visible (bool visible)
+{
+  priv->visible = visible;
+}
+
+
+/*
+ *	Menu::set_ticked - tick or untick a menu item
+ *
+ *	If <ticked> is true, item number <item_no> is ticked. If
+ *	<ticked> is false, item number <item_no> is unticked.
+ *	If the menu item was not created with the MIF_STICK
+ *	option, emit a warning and return without doing
+ *	anything.
+ */
+void Menu::set_ticked (size_t item_no, bool ticked)
+{
+  if (item_no >= priv->items.size ())
+  {
+    nf_bug ("Menu::set_ticked: item_no %lu", (unsigned long) item_no);
+    return;
+  }
+  Menu_item& i = priv->items[item_no];
+  if ((i.flags & MIF_MTICK) != MIF_STICK)
+  {
+    nf_bug ("Menu::set_ticked: flags %02X", i.flags);
+    return;
+  }
+  i.tick.s = ticked;
+}
+
+
+/*
+ *	Menu::set_active - grey-out or ungrey-out a menu
+ *
+ *	If <active> is false, item number <item_no> becomes
+ *	greyed out. If <active> is true, item number <item_no>
+ *	ceases to be greyed out. If the item was not created
+ *	with with the MIF_SACTIVE option, emit a warning and
+ *	return without doing anything.
+ */
+void Menu::set_active (size_t item_no, bool active)
+{
+  if (item_no >= priv->items.size ())
+  {
+    nf_bug ("Menu::set_active: item_no %lu", (unsigned long) item_no);
+    return;
+  }
+  Menu_item& i = priv->items[item_no];
+  if ((i.flags & MIF_MACTIVE) != MIF_SACTIVE)
+  {
+    nf_bug ("Menu::set_active: flags %02Xh", i.flags);
+    return;
+  }
+  i.active.s = active;
+}
+
+
+/*
+ *	Menu_priv::geom - recalculate the screen coordinates etc.
+ */
+void Menu_priv::geom ()
+{
+  size_t width_chars = 0;
+  if (title && (flags & MF_POPUP))
+    width_chars = y_max (width_chars, title_len);
+  if (flags & MF_NUMS)
+    width_chars = y_max (width_chars, items_len + 4);
+  else
+    width_chars = y_max (width_chars, items_ks_len);
+  int title_height = title && (flags & MF_POPUP) ? (int) (1.5 * FONTH) : 0;
+
+  width  = 2 * BOX_BORDER + 2 * WIDE_HSPACING + width_chars * FONTW;
+  height = 2 * BOX_BORDER + 2 * WIDE_VSPACING + title_height
+					      + items.back().y
+					      + item_height;
+
+  if (user_ox0 < 0)
+    ox0 = (ScrMaxX - width) / 2;
+  else
+    ox0 = user_ox0;
+  ix0 = ox0 + BOX_BORDER;
+  ix1 = ix0 + 2 * WIDE_HSPACING + width_chars * FONTW - 1;
+  ox1 = ix1 + BOX_BORDER;
+  if (ox1 > ScrMaxX)
+  {
+    int overlap = ox1 - ScrMaxX;
+    ox0 -= overlap;
+    ix0 -= overlap;
+    ix1 -= overlap;
+    ox1 -= overlap;
+  }
+
+  if (user_oy0 < 0)
+    oy0 = (ScrMaxY - height) / 2;
+  else
+    oy0 = user_oy0;
+  iy0 = oy0 + BOX_BORDER;
+  ty0 = iy0 + FONTH / 2;				// Title of menu
+  ly0 = ty0 + title_height;				// First item of menu
+
+  oy1 = oy0 + height - 1;
+  iy1 = oy1 - BOX_BORDER;
+
+  need_geom = false;
+}
+
+
+/*
+ *	Menu::process_event - process an input event
+ *
+ *	Process event in *<is>.
+ *
+ *	Return one of the following :
+ *	- MEN_CANCEL: user pressed [Esc] or clicked outside
+ *	  the menu. The caller should delete the menu.
+ *	- MEN_INVALID: we didn't understand the event so we put it
+ *	  back in the input buffer.
+ *	- MEN_OTHER: we understood the event and processed it.
+ *	- the number of the item that was validated.
+ */
+int Menu::process_event (const input_status_t *is)
+{
+  return priv->process_event (is);
+}
+
+
+int Menu_priv::process_event (const input_status_t *is)
+{
+  size_t mouse_line;
+  char status;
+
+  if ((int) is->x < ix0 || (int) is->x > ix1 || (int) is->y < ly0)
+    mouse_line = items.size ();
+  else
+  {
+    for (mouse_line = 0; mouse_line < items.size (); mouse_line++)
+      if ((int) is->y >= ly0 + items[mouse_line].y
+	&& (int) is->y < ly0 + items[mouse_line].y + item_height)
+	break;
+  }
+
+  status = 'i';
+
+  // Clicking left button on an item: validate it.
+  if (is->key == YE_BUTL_PRESS && mouse_line < items.size ())
+  {
+    line = mouse_line;  // Useless ?
+    status = 'v';
+  }
+
+  // Moving over the box sets current line.
+  else if (is->key == YE_MOTION && mouse_line < items.size ())
+  {
+    line = mouse_line;
+    status = 'o';
+  }
+
+  /* Releasing the button while standing on an item: has a
+     different effect depending on whether we're in pull-down or
+     pop-up mode.
+
+     In pull-down mode, the button was normally last pressed on
+     the menu bar or on an item of this menu. So the current
+     item is selected upon button release.
+
+     In pop-up mode, if the button was pressed, it was most
+     likely to exit a submenu (cf. the "thing type" menu) so we
+     ignore the event. */
+  else if (is->key == YE_BUTL_RELEASE
+	&& mouse_line < items.size ()
+	&& ! (flags & MF_POPUP))
+    status = 'v';
+
+  // [Enter], [Return]: accept selection
+  else if (is->key == YK_RETURN)
+    status = 'v';
+
+  // [Esc]: cancel
+  else if (is->key == YK_ESC)
+    status = 'c';
+
+  // [Up]: select previous line
+  else if (is->key == YK_UP)
+  {
+    if (line > 0)
+      line--;
+    else
+      line = items.size () - 1;
+    status = 'o';
+  }
+
+  // [Down]: select next line
+  else if (is->key == YK_DOWN)
+  {
+    if (line < items.size () - 1)
+      line++;
+    else
+      line = 0;
+    status = 'o';
+  }
+
+  // [Home]: select first line
+  else if (is->key == YK_HOME)
+  {
+    line = 0;
+    status = 'o';
+  }
+
+  // [End]: select last line
+  else if (is->key == YK_END)
+  {
+    line = items.size () - 1;
+    status = 'o';
+  }
+
+  // [Pgup]: select line - 5
+  else if (is->key == YK_PU)
+  {
+    if (line >= 5)
+      line -= 5;
+    else
+      line = 0;
+    status = 'o';
+  }
+
+  // [Pgdn]: select line + 5
+  else if (is->key == YK_PD)
+  {
+    if (line + 5 < items.size ())
+      line += 5;
+    else
+      line = items.size () - 1;
+    status = 'o';
+  }
+
+  // [1]-[9]: select items 0 through 8
+  else if ((flags & MF_NUMS)
+    && is->key < YK_
+    && within (dectoi (is->key), 1, items.size ()))
+  {
+    line = dectoi (is->key) - 1;
+    status = 'o';
+    send_event (YK_RETURN);
+  }
+
+  // [a]-[z]: select items 9 through 34
+  else if ((flags & MF_NUMS)
+    && is->key < YK_
+    && islower (is->key)
+    && within (b36toi (is->key), 10, items.size ()))
+  {
+    line = b36toi (is->key) - 1;
+    status = 'o';
+    send_event (YK_RETURN);
+  }
+
+  // [A]-[Z]: select items 35 through 60
+  else if ((flags & MF_NUMS)
+    && is->key < YK_
+    && isupper (is->key)
+    && within (b36toi (is->key) + 26, 36, items.size ()))
+  {
+    line = b36toi (is->key) + 25;
+    status = 'o';
+    send_event (YK_RETURN);
+  }
+
+  // A shortcut ?
+  else
+  {
+    /* First, check the list of tilde shortcuts
+       (only if is->key is a regular key) */
+    if ((flags & MF_TILDE)
+        && ! (flags & MF_NUMS)
+        && is->key == (unsigned char) is->key)
+    {
+      for (size_t n = 0; n < items.size (); n++)
+	if (items[n].tilde_key != YK_
+	    && items[n].tilde_key == tolower (is->key))
+	{
+	  line = n;
+	  status = 'o';
+	  send_event (YK_RETURN);
+	  break;
+	}
+    }
+    /* If no tilde shortcut matched, check the list of shortcut
+       keys. It's important to do the tilde shortcuts first so
+       that you can override a shortcut key (normally global)
+       with a tilde shortcut (normally local). */
+    if (status == 'i' && (flags & MF_SHORTCUT) && ! (flags & MF_NUMS))
+    {
+      for (size_t n = 0; n < items.size (); n++)
+	if (items[n].shortcut_key != YK_
+	    && items[n].shortcut_key == is->key)
+	{
+	  line = n;
+	  status = 'o';
+	  send_event (YK_RETURN);
+	  break;
+	}
+    }
+  }
+
+  // See last_shortcut_key()
+  if (status == 'v')
+    _last_shortcut_key = (flags & MF_SHORTCUT) ? items[line].shortcut_key : 0;
+
+  /* Return
+     - the item# if validated,
+     - MEN_CANCEL if cancelled,
+     - MEN_OTHER or MEN_INVALID if neither. */
+  if (status == 'v')
+    return (int) line;
+  else if (status == 'c')
+    return MEN_CANCEL;
+  else if (status == 'o')
+    return MEN_OTHER;
+  else if (status == 'i')
+    return MEN_INVALID;
+  else
+  {
+    // Can't happen
+    fatal_error ("Menu::process_event: bad status %02Xh", status);
+    return 0;  // To please the compiler
+  }
+}
+
+
+/*
+ *	Menu::last_shortcut_key - shortcut key for last selected item
+ *
+ *	Return the code of the shortcut key for the last
+ *	selected item. This function shouldn't exist : it's just
+ *	there because it helps editloop.cc. When real key
+ *	bindings are implemented in editloop.cc,
+ *	get_shortcut_key() should disappear.
+ */
+inpev_t Menu::last_shortcut_key ()
+{
+  return priv->_last_shortcut_key;
+}
+
+
+/*
+ *	Menu::draw - display the menu
+ *
+ *	If necessary, redraw everything from scratch. Else, if
+ *	<line> has changed, refresh the highlighted line.
+ */
+void Menu::draw ()
+{
+  priv->draw ();
+}
+
+
+void Menu_priv::draw ()
+{
+  bool from_scratch = false;
+
+  if (need_geom)
+    geom ();
+
+  // Do we need to redraw everything from scratch ?
+  if (visible && ! visible_disp
+    || ox0    != ox0_disp
+    || oy0    != oy0_disp
+    || width  != width_disp
+    || height != height_disp)
+    from_scratch = true;
+
+  // Display the static part of the menu
+  if (from_scratch)
+  {
+    HideMousePointer ();
+    DrawScreenBox3D (ox0, oy0, ox1, oy1);
+    set_colour (WINTITLE);
+    if ((flags & MF_POPUP) && title != 0)
+      DrawScreenString (ix0 + WIDE_HSPACING, ty0, title);
+    ShowMousePointer ();
+
+    for (size_t l = 0; l < items.size (); l++)
+    {
+      set_colour (WINFG);
+      draw_one_line (l, false);
+    }
+    visible_disp = true;
+    ox0_disp     = ox0;
+    oy0_disp     = oy0;
+    width_disp   = width;
+    height_disp  = height;
+  }
+
+  // Display the "highlight" bar
+  if (from_scratch || line != line_disp)
+  {
+    if (line_disp < items.size ())
+      draw_one_line (line_disp, false);
+    if (line < items.size ())
+      draw_one_line (line, true);
+    line_disp = line;
+  }
+}
+
+
+/*
+ *	Menu::draw_one_line - display just one line of a menu
+ *
+ *  	<line> is the number of the option to draw (0 = first
+ *  	option). <highlighted> tells whether the option should
+ *  	be drawn highlighted.
+ */
+void Menu_priv::draw_one_line (size_t line, bool highlighted)
+{
+  const Menu_item& i = items[line];
+  int x      = ix0 + FONTW;
+  int y      = ly0 + i.y;
+  int text_y = y + VSPACE / 2;
+
+  HideMousePointer ();
+
+  // Separation ?
+  if (i.flags & MIF_SEPAR)
+  {
+    push_colour (WINBG_DARK);
+    short groove_y = y - NARROW_VSPACING - 2 * NARROW_BORDER;
+    DrawScreenLine (ix0, groove_y, ix1, groove_y);
+    set_colour (WINBG_LIGHT);
+    DrawScreenLine (ix0, groove_y + 1, ix1, groove_y + 1);
+    pop_colour ();
+  }
+
+  // Greyed out ?
+  bool active = true;
+  switch (i.flags & MIF_MACTIVE)
+  {
+    case MIF_NACTIVE:
+      active = true;
+      break;
+
+    case MIF_SACTIVE:
+      active = i.active.s;
+      break;
+
+    case MIF_VACTIVE:
+      active = *i.active.v;
+      break;
+
+    case MIF_FACTIVE:
+      active = i.active.f.f (i.active.f.a);
+      break;
+
+    default:
+      nf_bug ("Menu::draw_one_line: active %02Xh", i.flags);
+      break;
+  }
+  set_colour (menu_colour[! active][highlighted].bg);
+  DrawScreenBox (ix0, y, ix1, y + item_height - 1);
+  set_colour (menu_colour[! active][highlighted].fg);
+
+  // Tick mark if any
+  if (flags & MF_TICK)
+  {
+    bool have_tick = false;
+    bool ticked    = false;
+    switch (i.flags & MIF_MTICK)
+    {
+      case MIF_NTICK:
+        have_tick = false;
+        break;
+
+      case MIF_STICK:
+	have_tick = true;
+        ticked    = i.tick.s;
+        break;
+
+      case MIF_VTICK:
+        have_tick = true;
+        ticked    = *i.tick.v;
+        break;
+
+      case MIF_FTICK:
+        have_tick = true;
+        ticked    = i.tick.f.f (i.tick.f.a);
+        break;
+
+      default:
+        nf_bug ("Menu::draw_one_line: tick %02Xh", i.flags);
+        break;
+    }
+    if (have_tick)
+    {
+      if (ticked)
+      {
+	unsigned hside = FONTW * 4 / 5;
+	unsigned vside = FONTH * 4 / 5;
+	int x0 = x + (FONTW - hside) / 2;
+	int y0 = y + (FONTH - vside) / 2;
+	DrawScreenLine (x0, y0 + vside / 2, x0 + hside / 2, y0 + vside - 1);
+	DrawScreenLine (x0 + hside / 2, y0 + vside - 1, x0 + hside - 1, y0);
+      }
+      else
+      {
+	unsigned margin = FONTW / 5;
+	DrawScreenLine (x + margin,             y + FONTH / 2,
+			x + FONTW - 1 - margin, y + FONTH / 2);
+      }
+    }
+    x += 2 * FONTW;
+  }
+
+  // Automatic keys if any
+  if (flags & MF_NUMS)
+  {
+    char c = '\0';
+    if (line <= 8)
+      c = '1' + line;
+    else if (line >= 9 && line < 9 + 26)
+      c = 'a' + line - 9;
+    else if (line >= 9 + 26 && line < 9 + 26 + 26)
+      c = 'A' + line - (9 + 26);
+    if (c != '\0')
+    {
+      push_colour (highlighted ? WINLABEL_HL : WINLABEL);
+      DrawScreenString (x, text_y, "[ ]");
+      pop_colour ();
+      DrawScreenChar (x + FONTW, text_y,         c);
+      DrawScreenChar (x + FONTW, text_y + FONTU, '_');
+    }
+    x += 4 * FONTW;
+  }
+
+  // Text
+  int tilde_index = -1;
+  {
+    const char *str = (flags & MF_MENUDATA) ? (*menudata)[line] : i.str;
+    char *buf = new char[strlen (str) + 1]; 
+    char *d   = buf;
+    for (const char *s = str; *s != '\0'; s++)
+    {
+      if (*s == '~' && tilde_index < 0)
+      {
+	tilde_index = s - str;
+	continue;
+      }
+      *d++ = *s;
+    }
+    *d = '\0';
+    DrawScreenString (x, text_y, buf);
+    delete[] buf;
+  }
+
+  // Underscore the tilde shortcut if any
+  if (! (flags & MF_NUMS) && tilde_index >= 0)
+    DrawScreenString (x + tilde_index * FONTW, text_y + FONTU, "_");
+
+  // Shortcut key if any
+  if (! (flags & MF_NUMS) && i.shortcut_key != YK_)
+  {
+    const char *s = key_to_string (i.shortcut_key);
+    DrawScreenString (ix1 + 1 - FONTW - strlen (s) * FONTW, text_y, s);
+  }
+  ShowMousePointer ();
+}
+
+
+/*
+ *	WIDGET METHODS
+ */
+
+
+void Menu::undraw ()
+{
+  ;  // I can't undraw myself
+}
+
+
+int Menu::can_undraw ()
+{
+  return 0;  // I can't undraw myself
+}
+
+
+int Menu::need_to_clear ()
+{
+  return ! priv->visible && priv->visible_disp || priv->need_geom;
+}
+
+
+void Menu::clear ()
+{
+  priv->visible_disp = false;
+}
+
+
+int Menu::req_width ()
+{
+  if (priv->need_geom)
+    priv->geom ();
+  return priv->width;
+}
+
+
+int Menu::req_height ()
+{
+  if (priv->need_geom)
+    priv->geom ();
+  return priv->height;
+}
+
+
+int Menu::get_x0 ()
+{
+  return priv->ox0_disp;
+}
+
+
+int Menu::get_y0 ()
+{
+  return priv->oy0_disp;
+}
+
+
+int Menu::get_x1 ()
+{
+  return priv->ox0_disp + priv->width_disp - 1;
+}
+
+
+int Menu::get_y1 ()
+{
+  return priv->oy0_disp + priv->height_disp - 1;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/menu.h	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,121 @@
+/*
+ *	menu.h
+ *	AYM 1998-08-15
+ */
+
+
+/*
+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.
+*/
+
+
+#ifndef YH_MENUS  /* DO NOT INSERT ANYTHING BEFORE THIS LINE */
+#define YH_MENUS
+
+
+#include <stdarg.h>
+#include <vector>
+#include "edwidget.h"
+
+
+typedef struct 
+{
+  acolour_t bg;
+  acolour_t fg;
+} colour_pair_t;
+
+/* First subscript :  0 = normal, 1 = greyed out
+   Second subscript : 0 = normal, 1 = highlighted */
+extern const colour_pair_t menu_colour[2][2];
+
+const unsigned char MIF_NACTIVE = 0;
+const unsigned char MIF_SACTIVE = 1;
+const unsigned char MIF_VACTIVE = 2;
+const unsigned char MIF_FACTIVE = 3;
+
+const unsigned char MIF_NTICK = 0 << 2;
+const unsigned char MIF_STICK = 1 << 2;
+const unsigned char MIF_VTICK = 2 << 2;
+const unsigned char MIF_FTICK = 3 << 2;
+
+extern const char *MI_SEPARATION;
+
+typedef void *micbarg_t;		// Argument of callback function
+typedef bool (*micb_t) (micbarg_t);	// Pointer to callback function
+
+// Values returned by process_event()
+const int MEN_CANCEL  = -1;  // Exit by [Esc]. Caller should destroy the menu.
+const int MEN_OTHER   = -2;  // Got other event and processed it.
+const int MEN_INVALID = -3;  // Got invalid event. Caller should process it.
+
+
+class Menu_data;
+class Menu_priv;
+
+
+/*
+ *	Menu - a menu class
+ */
+class Menu : public edwidget_c
+{
+  public :
+    // Ctors
+    Menu (const char *title, ...);
+    Menu (const char *title, va_list argp);
+    Menu (const char *title, al_llist_t *list, const char *(*getstr)(void *));
+    Menu (const char *title, const Menu_data& menudata);
+    ~Menu ();
+
+    // Configuration
+    void set_coords (int x, int y);
+    void set_title (const char *title);
+    void set_item_no (int item_no);
+    void set_popup (bool popup);
+    void set_force_numbers (bool force_numbers);
+    void set_visible (bool visible);
+    void set_ticked (size_t item_no, bool ticked);
+    void set_active (size_t item_no, bool active);
+
+    // Event processing
+    int process_event (const input_status_t *is);
+    inpev_t last_shortcut_key ();
+
+    // Widget functions
+    void draw ();
+    void undraw ();
+    int can_undraw ();
+    int need_to_clear ();
+    void clear ();
+    int req_width ();
+    int req_height ();
+    int get_x0 ();
+    int get_y0 ();
+    int get_x1 ();
+    int get_y1 ();
+
+  private :
+    Menu (const Menu&);			// Too lazy to implement it
+    Menu& operator= (const Menu&);	// Too lazy to implement it
+    Menu_priv *priv;
+};
+
+
+#endif  /* DO NOT ADD ANYTHING AFTER THIS LINE */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/menubar.cc	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,409 @@
+/*
+ *	menubar.cc
+ *	AYM 1998-08-21
+ */
+
+
+/*
+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.
+*/
+
+
+/*
+This modules contains (almost) all the functions related to the
+menu bar.
+
+CAVEATS
+
+One thing that I didn't even attempt to handle is the case where
+the screen/window is not large enough to hold all the menu items.
+This will cause the left-aligned and right-aligned items to overlap
+and even to "go off" the screen/window.
+
+AYM 1998-08-21
+*/
+
+
+#include "yadex.h"
+#include "gfx.h"
+#include "menubar.h"
+#include "menu.h"
+
+
+/*
+ *	menubar_c
+ */
+menubar_c::menubar_c ()
+{
+stale_coords          = 1;
+nitems                = 0;
+stale_x0_x1           = 1;
+spacing               = FONTW;
+bar_visible           = 1;
+bar_visible_disp      = 0;
+highlighted_no        = -1;
+highlighted_no_disp   = -1;
+pulled_down_no        = -1;
+pulled_down_no_disp   = -1;
+pulled_down_menu      = 0;
+pulled_down_menu_disp = 0;
+#if 0
+for (size_t n = 0; n < MAX_ITEMS; n++)
+   {
+   item_menu[n] = 0;
+   }
+#endif
+}
+
+
+/*
+ *	compute_menubar_coords
+ *	Call this one second and each time the screen size
+ *	changes.
+ *	(<scrx0>, <scry0>) are the coordinates
+ *	of the top left corner of the screen/window.
+ *	(<scrx1>, <scry1>) are the coordinates
+ *	of the bottom right corner of the screen/window.
+ */
+void menubar_c::compute_menubar_coords (int scrx0, int scry0, int scrx1, int scry1)
+{
+// Just to prevent the compiler from emitting an
+// annoying warning about that parameter being unused.
+scry1 = 0;
+
+menubar_out_x0  = scrx0;
+menubar_in_x0   = menubar_out_x0 + BOX_BORDER;
+menubar_text_x0 = menubar_in_x0;
+
+menubar_out_x1  = scrx1;
+menubar_in_x1   = menubar_out_x1 - BOX_BORDER;
+menubar_text_x1 = menubar_in_x1;
+
+menubar_out_y0  = scry0;
+menubar_in_y0   = menubar_out_y0  + BOX_BORDER;
+menubar_text_y0 = menubar_in_y0   + NARROW_VSPACING;
+menubar_text_y1 = menubar_text_y0 + FONTH - 1;
+menubar_in_y1   = menubar_text_y1 + NARROW_VSPACING;
+menubar_out_y1  = menubar_in_y1   + BOX_BORDER;
+
+stale_coords = 0;
+stale_x0_x1 = 1;
+}
+
+
+/*
+ *	add_menubar_item
+ *	Add a new item to the menu bar.
+ *	If <right_aligned> is non zero, that item will be
+ *	right aligned on the menu bar.
+ *	Returns the number of the newly created item.
+ */
+int menubar_c::add_item (const char *text, int shortcut_index,
+   int right_aligned, Menu *menu)
+{
+if (nitems >= MAX_ITEMS)
+   fatal_error ("Too many items on menu bar");
+if (shortcut_index < 0 || shortcut_index >= (int) strlen (text))
+   fatal_error ("add_menubar_item: shortcut_index out of range");
+item_text[nitems]           = text;
+item_shortcut_index[nitems] = shortcut_index;
+item_right_aligned[nitems]  = right_aligned;
+item_menu[nitems]           = menu;
+nitems++;
+stale_x0_x1 = 1;
+return nitems - 1;
+}
+
+
+/*
+ *	set_menu
+ *	Change the menu for an existing menu bar item.
+ */
+void menubar_c::set_menu (int number, Menu *menu)
+{
+if (number >= nitems)
+   fatal_error ("set_menu: bad mbi#");
+item_menu[number] = menu;
+
+// So that need_to_clear() knows something has changed
+if (number == pulled_down_no)
+   pulled_down_menu = menu;
+}
+
+
+/*
+ *	get_menu
+ *	Return a pointer on the menu for an existing menu bar item.
+ */
+Menu *menubar_c::get_menu (int number)
+{
+if (number >= nitems)
+   fatal_error ("set_menu: bad mbi#");
+return item_menu[number];
+}
+
+
+/*
+ *	highlight
+ *	Highlight the menu bar item number <number>.
+ *	Use <number> < 0 to clear the highlighting.
+ */
+void menubar_c::highlight (int number)
+{
+highlighted_no = number;
+if (pulled_down_no >= 0)
+   {
+   pulled_down_no = number;
+   if (number >= 0)
+      pulled_down_menu = item_menu[number];
+   else
+      pulled_down_menu = 0;
+   }
+}
+
+
+/*
+ *	highlighted
+ *	Return the number of the menu bar item that is highlighted
+ *	or < 0 if none.
+ */
+int menubar_c::highlighted ()
+{
+return highlighted_no;
+}
+
+
+/*
+ *	pull_down
+ *	Pull down the menu under the menu bar item number <number>.
+ *	Use <number> < 0 to "unroll".
+ */
+void menubar_c::pull_down (int number)
+{
+if (number >= 0 && number != pulled_down_no)
+   item_menu[number]->set_item_no (0);
+
+pulled_down_no = number;
+
+if (number >= 0)
+   {
+   pulled_down_menu = item_menu[number];
+   // Pulling down a menu implies highlighting
+   // the corresponding item on the menu bar.
+   highlight (number);
+   }
+else
+   pulled_down_menu = 0;
+}
+
+
+/*
+ *	pulled_down
+ *	Return the number of the menu bar item that is pulled down
+ *	or < 0 if none.
+ */
+int menubar_c::pulled_down ()
+{
+return pulled_down_no;
+}
+
+
+/*
+ *	clear
+ */
+void menubar_c::clear ()
+{
+//for (int n = 0; n < nitems; n++)
+//   item_menu[n]->clear ();
+
+if (pulled_down_menu_disp)
+   pulled_down_menu_disp->clear ();
+bar_visible_disp      = 0;
+highlighted_no_disp   = -1;
+pulled_down_no_disp   = -1;
+pulled_down_menu_disp = 0;
+}
+
+
+/*
+ *	draw
+ *	Draw the menu bar according to its current state.
+ */
+void menubar_c::draw ()
+{
+// Draw the menu bar itself
+if (bar_visible && ! bar_visible_disp
+   || highlighted_no != highlighted_no_disp)
+   {
+   if (stale_x0_x1)
+      compute_x0_x1 ();
+   push_colour (menu_colour[0][0].bg);  /* 1 */
+   DrawScreenBox3D (0, 0, ScrMaxX, menubar_out_y1);
+   set_colour (menu_colour[0][0].fg);
+   for (int n = 0; n < nitems; n++)
+      {
+      if (n == highlighted_no)
+	 {
+	 push_colour (menu_colour[0][1].bg);  /* 2 */
+	 DrawScreenBox (item_x0[n], menubar_in_y0, item_x1[n], menubar_in_y1);
+	 set_colour (menu_colour[0][1].fg);
+	 }
+      DrawScreenString (item_x0[n] + spacing, menubar_text_y0, item_text[n]);
+      DrawScreenString (item_x0[n] + spacing + item_shortcut_index[n] * FONTW,
+		      menubar_text_y0 + FONTU, "_");
+      if (n == highlighted_no)
+	 pop_colour ();  /* 2 */
+      }
+   pop_colour ();  /* 1 */
+   bar_visible_disp    = 1;
+   highlighted_no_disp = highlighted_no;
+   }
+
+// If there is a menu that used to be visible
+// but isn't anymore, let it be aware of it.
+if (pulled_down_menu_disp && pulled_down_menu != pulled_down_menu_disp)
+   {
+   pulled_down_menu_disp->clear ();
+   pulled_down_menu_disp->set_visible (0);
+   }
+
+// Draw the pulled down menu (if any)
+if (pulled_down_menu)
+   {
+   int x, y;
+   menubar_item_coords (pulled_down_no, &x, &y);
+   pulled_down_menu->set_popup         (0);
+   pulled_down_menu->set_force_numbers (0);
+   pulled_down_menu->set_coords        (x, y);
+   pulled_down_menu->set_visible       (1);
+   pulled_down_menu->draw              ();
+   }
+
+pulled_down_no_disp   = pulled_down_no;
+pulled_down_menu_disp = pulled_down_menu;
+}
+
+
+/*
+ *	is_on_menubar_item
+ *	Returns the number of the menu bar item which should
+ *	be pulled down if the user clicked at screen coords (x,y).
+ *	Returns -1 if none.
+ */
+int menubar_c::is_on_menubar_item (int x, int y)
+{
+if (stale_coords)
+   fatal_error ("Called iomi before cc");
+if (x < menubar_in_x0 || x > menubar_in_x1
+ || y < menubar_in_y0 || y > menubar_in_y1)
+   return -1;
+if (stale_x0_x1)
+   compute_x0_x1 ();
+for (int n = 0; n < nitems; n++)
+   if (x >= item_x0[n] && x <= item_x1[n])
+      return n;
+return -1;
+}
+
+
+/*
+ *	is_under_menubar_item
+ *	Returns whether the screen abscissa <scrx> is "under"
+ *	(or "over") one of the menu bar items.
+ *	This weird function is used in only one place ; the
+ *	autoscroll code. If the mouse pointer is at the same
+ *	abscissa as a menubar item, it probably means that the
+ *	user is reaching for the menus so don't scroll.
+ */
+int menubar_c::is_under_menubar_item (int scrx)
+{
+if (stale_coords)
+   fatal_error ("Called iumi before cc");
+if (stale_x0_x1)
+   compute_x0_x1 ();
+for (int n = 0; n < nitems; n++)
+   if (scrx >= item_x0[n] && scrx <= item_x1[n])
+      return n;
+return -1;
+}
+
+
+/*
+ *	compute_x0_x1
+ *	Fill in item_x0 and item_x1.
+ */
+void menubar_c::compute_x0_x1 ()
+{
+int x_left;
+int x_right;
+int n;
+
+if (stale_coords)
+   fatal_error ("Called compute_x0_x1 before compute_coords");
+x_left  = menubar_text_x0;
+x_right = menubar_text_x1;
+for (n = 0; n < nitems; n++)
+   {
+   int item_width = 2 * spacing + strlen (item_text[n]) * FONTW;
+
+   /* This item is right-aligned ?
+      Place it to the left of the last right-aligned item. */
+   if (item_right_aligned[n])
+      {
+      item_x1[n] = x_right;
+      x_right -= item_width;
+      item_x0[n] = x_right + 1;
+      }
+
+   /* It's left-aligned.
+      Place it to the right of the last left-aligned item. */
+   else
+      {
+      item_x0[n] = x_left;
+      x_left += item_width;
+      item_x1[n] = x_left - 1;
+      }
+   }
+stale_x0_x1 = 0;
+}
+
+
+/*
+ *	menubar_item_coords
+ *	Returns coordinates of top left corner of a pulled down
+ *	menu.
+ *	This function will be removed when menus are pulled down
+ *	by menubar.cc itself.
+ */
+void menubar_c::menubar_item_coords (int item_no, int *x, int *y)
+{
+if (item_no < 0 || item_no >= nitems)
+   fatal_error ("menubar_item_coords passed bad item no. %d", item_no);
+if (stale_coords)
+   fatal_error ("Called menubar_item_coords before compute_coords");
+if (stale_x0_x1)
+   compute_x0_x1 ();
+*x = item_x0[item_no];
+*y = menubar_out_y1 + 1;
+}
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/menubar.h	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,124 @@
+/*
+ *	menubar.h
+ *	Header for menubar.c
+ *	AYM 1998-08-21
+ */
+
+
+/*
+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.
+*/
+
+
+/*
+The menubar widget keeps the following state information ;
+- whether the menu bar should be displayed (always true),
+- whether the menu bar is actually displayed,
+- the number of the item that should be highlighted (sometimes "none"),
+- the number of the item that is actually highlighted (sometimes "none"),
+- the number of the menu that should be pulled down (sometimes "none"),
+- the number of the menu that is actually pulled down (sometimes "none")
+- a pointer on the menu that should be pulled down (sometimes "none"),
+- a pointer on the menu that is actually pulled down (sometimes "none")
+*/
+
+
+#include "edwidget.h"
+class Menu;
+
+
+static const int MAX_ITEMS = 10;
+
+
+class menubar_c : public edwidget_c
+   {
+   public :
+      menubar_c ();
+
+      int add_item (const char *text, int shortcut_index, int right_aligned,
+         Menu *menu);
+      void set_menu (int number, Menu *menu);
+      Menu *get_menu (int number);
+      void compute_menubar_coords (int scrx0, int scrx1, int scry0, int scry1);
+      void highlight (int number);
+      void pull_down (int number);
+      int highlighted ();
+      int pulled_down ();
+      int is_on_menubar_item (int scrx, int scry);
+      int is_under_menubar_item (int scrx);
+      void menubar_item_coords (int item_no, int *x, int *y);
+
+      /*
+       *	widget
+       */
+      void draw ();
+      void undraw () { }  // I can't undraw myself
+      int can_undraw () { return 0; }  // I can't undraw myself
+
+      int need_to_clear ()
+         {
+         return bar_visible_disp && ! bar_visible
+            || pulled_down_no_disp && ! pulled_down_no
+            || pulled_down_menu_disp != pulled_down_menu;
+         }
+
+      void clear ();
+
+   private :
+      void compute_x0_x1 ();
+
+      int spacing;          		// Horizontal spacing around item name
+
+      int stale_coords;			// Should menubar_* be recalculated ?
+      int menubar_out_x0;		// Edge of the menu bar, includ. border
+      int menubar_out_x1;
+      int menubar_out_y0;
+      int menubar_out_y1;
+      int menubar_in_x0;		// Edge of the menu bar, exclud. border
+      int menubar_in_x1;
+      int menubar_in_y0;
+      int menubar_in_y1;
+      int menubar_text_x0;		// Edge of the text area of the menu bar
+      int menubar_text_x1;
+      int menubar_text_y0;
+      int menubar_text_y1;
+
+      int nitems;			// Number of items
+      const char *item_text[MAX_ITEMS];	// Definition of items
+      int item_shortcut_index[MAX_ITEMS];
+      int item_right_aligned[MAX_ITEMS];
+      Menu *item_menu[MAX_ITEMS];
+       
+      int stale_x0_x1;         		// Should item_x? be recalculated ?
+      int item_x0[MAX_ITEMS];		// Left edge of items, includ. spacing
+      int item_x1[MAX_ITEMS];		// Right edge of items, includ. spacing
+
+      int bar_visible;			// Should the bar be visible ?
+      int bar_visible_disp;		// Is the bar actually visible ?
+      int highlighted_no;		// # of the item that should be h.l.
+      int highlighted_no_disp;		// # of the item that is actually h.l.
+      int pulled_down_no;		// # of menu that should be p.d.
+      int pulled_down_no_disp;		// # of menu that is actually p.d.
+      Menu *pulled_down_menu;		// Menu that should be p.d.
+      Menu *pulled_down_menu_disp;	// Menu that is actually p.d.
+   };
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/menudata.h	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,42 @@
+/*
+ *	menudata.h - Menu_data abstract base class
+ *	AYM 2002-05-09
+ */
+
+
+/*
+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-2002 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.
+*/
+
+
+#ifndef YH_MENUDATA  /* DO NOT INSERT ANYTHING BEFORE THIS LINE */
+#define YH_MENUDATA
+
+
+class Menu_data
+{
+  public :
+    virtual size_t nitems () const = 0;
+    virtual const char *operator[] (size_t n) const = 0;
+};
+
+
+#endif  /* DO NOT ADD ANYTHING AFTER THIS LINE */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/mkpalette.cc	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,290 @@
+/*
+ *	mkpalette.cc
+ *	Generate palette files from lump PLAYPAL.
+ *	AYM 1998-12-29
+ */
+
+
+/*
+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 "mkpalette.h"
+#include "gfx.h"
+#include "rgb.h"
+#include "wadfile.h"
+#include "wads.h"
+
+
+/*
+ *	make_gimp_palette
+ *	Generate a Gimp palette file for the <playpalnum>th
+ *	palette in the PLAYPAL entry.
+ *	Return 0 on success, non-zero on failure.
+ */
+int make_gimp_palette (int playpalnum, const char *filename)
+{
+  int     rc        = 0;
+  MDirPtr dir;
+  u8	 *dpal      = 0;
+  FILE	 *output_fp = 0;
+
+  const char *lump_name = "PLAYPAL";
+  dir = FindMasterDir (MasterDir, lump_name);
+  if (dir == 0)
+  {
+    warn ("%s: lump not found\n",lump_name);
+    return 1;
+  }
+
+  int playpal_count = dir->dir.size / (3 * DOOM_COLOURS);
+  if (playpalnum < 0 || playpalnum >= playpal_count)
+  {
+    warn ("playpalnum %d out of range (0-%d), using #0 instead\n",
+      playpalnum, playpal_count - 1);
+    playpalnum = 0;
+  }
+
+  output_fp = fopen (filename, "w");
+  if (output_fp == 0)
+  {
+    warn ("%s: %s\n", filename, strerror (errno));
+    return 1;
+  }
+  fprintf (output_fp,
+     "GIMP Palette\n"
+     "# Generated by Yadex %s\n", yadex_version);
+
+  dpal = (u8 *) GetFarMemory (3 * DOOM_COLOURS);
+  const Wad_file *wf = dir->wadfile;
+  wf->seek (dir->dir.start + (long) playpalnum * 3 * DOOM_COLOURS);
+  if (wf->error ())
+  {
+    err ("%s: seek error", lump_name);
+    rc = 1;
+    goto byebye;
+  }
+  wf->read_bytes (dpal, 3 * DOOM_COLOURS);
+  if (wf->error ())
+  {
+    err ("%s: read error", lump_name);
+    rc = 1;
+    goto byebye;
+  }
+  for (size_t n = 0; n < DOOM_COLOURS; n++)
+    fprintf (output_fp, "%3d %3d %3d  Index = %d (%02Xh)   RGB = %d, %d, %d\n",
+      dpal[3 * n],
+      dpal[3 * n + 1],
+      dpal[3 * n + 2],
+      n,
+      n,
+      dpal[3 * n],
+      dpal[3 * n + 1],
+      dpal[3 * n + 2]);
+
+  byebye:
+  if (dpal != 0)
+    FreeFarMemory (dpal);
+  if (output_fp != 0)
+    if (fclose (output_fp))
+      return 1;
+  return rc;
+}
+
+
+/*
+ *	make_palette_ppm
+ *	Generate a 256 x 128 raw PPM image showing all the
+ *	colours in the palette.
+ *	Return 0 on success, non-zero on failure.
+ */
+int make_palette_ppm (int playpalnum, const char *filename)
+{
+  int     rc        = 0;
+  MDirPtr dir;
+  u8	 *dpal      = 0;
+  FILE	 *output_fp = 0;
+
+  const char *lump_name = "PLAYPAL";
+  dir = FindMasterDir (MasterDir, lump_name);
+  if (dir == 0)
+  {
+    warn ("%s: lump not found\n", lump_name);
+    return 1;
+  }
+
+  int playpal_count = dir->dir.size / (3 * DOOM_COLOURS);
+  if (playpalnum < 0 || playpalnum >= playpal_count)
+  {
+    warn ("playpalnum %d out of range (0-%d), using #0 instead\n",
+      playpalnum, playpal_count - 1);
+    playpalnum = 0;
+  }
+
+  output_fp = fopen (filename, "wb");
+  if (output_fp == 0)
+  {
+    warn ("%s: %s\n", filename, strerror (errno));
+    return 1;
+  }
+
+  const int width = 128;
+  const int height = 128;
+  const int columns = 16;
+
+  fputs ("P6", output_fp);
+  fnewline (output_fp);
+  fprintf (output_fp, "# Generated by Yadex %s", yadex_version);
+  fnewline (output_fp);
+  fprintf (output_fp, "%d %d", width, height);
+  fnewline (output_fp);
+  fputs ("255\n", output_fp);  // Always \n (must be a single character)
+
+  int rect_w = width / columns;
+  int rect_h = height / (DOOM_COLOURS / columns);
+
+  dpal = (u8 *) GetFarMemory (3 * DOOM_COLOURS);
+  const Wad_file *wf = dir->wadfile;
+  wf->seek (dir->dir.start + (long) playpalnum * 3 * DOOM_COLOURS);
+  if (wf->error ())
+  {
+    err ("%s: seek error", lump_name);
+    rc = 1;
+    goto byebye;
+  }
+  wf->read_bytes (dpal, 3 * DOOM_COLOURS);
+  if (wf->error ())
+  {
+    err ("%s: read error", lump_name);
+    rc = 1;
+    goto byebye;
+  }
+  for (size_t n = 0; n < DOOM_COLOURS; n += columns)
+    for (int subrow = 0; subrow < rect_h; subrow++)
+      for (int c = 0; c < columns; c++)
+	for (int subcol = 0; subcol < rect_w; subcol++)
+	{
+	  if (subrow == 0 && subcol == 0)
+	  {
+	    putc (0, output_fp);
+	    putc (0, output_fp);
+	    putc (0, output_fp);
+	  }
+	  else
+	  {
+	    putc (dpal[3 * (n + c)],     output_fp);
+	    putc (dpal[3 * (n + c) + 1], output_fp);
+	    putc (dpal[3 * (n + c) + 2], output_fp);
+	  }
+	}
+
+  byebye:
+  if (dpal != 0)
+    FreeFarMemory (dpal);
+  if (output_fp != 0)
+    if (fclose (output_fp))
+      return 1;
+  return rc;
+}
+
+
+/*
+ *	make_palette_ppm_2
+ *	Make a wide PPM containing all the colours in the palette
+ */
+
+int make_palette_ppm_2 (int playpalnum, const char *filename)
+{
+  int     rc        = 0;
+  MDirPtr dir;
+  u8	 *dpal      = 0;
+  FILE	 *output_fp = 0;
+
+  const char *lump_name = "PLAYPAL";
+  dir = FindMasterDir (MasterDir, lump_name);
+  if (dir == 0)
+  {
+    warn ("%s: lump not found", lump_name);
+    return 1;
+  }
+
+  int playpal_count = dir->dir.size / (3 * DOOM_COLOURS);
+  if (playpalnum < 0 || playpalnum >= playpal_count)
+  {
+    warn ("playpalnum %d out of range (0-%d), using #0 instead",
+      playpalnum, playpal_count - 1);
+    playpalnum = 0;
+  }
+
+  output_fp = fopen (filename, "wb");
+  if (output_fp == 0)
+  {
+    warn ("%s: %s\n", filename, strerror (errno));
+    return 1;
+  }
+
+  const int width = DOOM_COLOURS;
+  const int height = DOOM_COLOURS;
+
+  fputs ("P6", output_fp);
+  fnewline (output_fp);
+  fprintf (output_fp, "# Generated by Yadex %s", yadex_version);
+  fnewline (output_fp);
+  fprintf (output_fp, "%d %d", width, height);
+  fnewline (output_fp);
+  fputs ("255\n", output_fp);  // Always \n (must be a single character)
+
+  dpal = (u8 *) GetFarMemory (3 * DOOM_COLOURS);
+  const Wad_file *wf = dir->wadfile;
+  wf->seek (dir->dir.start + (long) playpalnum * 3 * DOOM_COLOURS);
+  if (wf->error ())
+  {
+    err ("%s: seek error", lump_name);
+    rc = 1;
+    goto byebye;
+  }
+  wf->read_bytes (dpal, 3 * DOOM_COLOURS);
+  if (wf->error ())
+  {
+    err ("%s: read error", lump_name);
+    rc = 1;
+    goto byebye;
+  }
+  for (int l = 0; l < height; l++)
+    for (int c = 0; c < width; c++)
+    {
+      putc (dpal[3 * ((c + l) % DOOM_COLOURS)    ], output_fp);
+      putc (dpal[3 * ((c + l) % DOOM_COLOURS) + 1], output_fp);
+      putc (dpal[3 * ((c + l) % DOOM_COLOURS) + 2], output_fp);
+    }
+
+  byebye:
+  if (dpal != 0)
+    FreeFarMemory (dpal);
+  if (output_fp != 0)
+    if (fclose (output_fp))
+      return 1;
+  return rc;
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/mkpalette.h	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,12 @@
+/*
+ *	mkpalette.h
+ *	Make palette files from lump PLAYPAL
+ *	AYM 1998-12-29
+ */
+
+
+int make_gimp_palette (int playpalnum, const char *filename);
+int make_palette_ppm (int playpalnum, const char *filename);
+int make_palette_ppm_2 (int playpalnum, const char *filename);
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/modpopup.h	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,122 @@
+/*
+ *	modpopup.h
+ *	The modpopup_c class: a modal popup menu widget.
+ *	Basically a wrapper for the Menu class.
+ *	AYM 1998-12-16
+ */
+
+
+/*
+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 "edwidget.h"
+#include "menu.h"
+
+
+class modpopup_c : public edwidget_c
+{
+  public :
+
+    /*
+     *	EditorLoop() side methods
+     */
+    modpopup_c ()
+    {
+      menu = 0;
+      menu_disp = 0;
+    }
+
+    void set (Menu *menu, int force_numbers)
+    {
+      if (menu_disp)
+	menu_disp->set_visible (0);
+      this->menu = menu;
+      menu->set_popup         (1);
+      menu->set_force_numbers (force_numbers);
+      menu->set_coords        (-1, -1);
+      menu->set_item_no       (0);
+      menu->set_visible       (1);
+    }
+
+    void unset ()
+    {
+      if (menu_disp)
+	menu_disp->set_visible (0);
+      menu = 0;
+    }
+
+    Menu *get ()
+    {
+      return menu;
+    }
+
+    /*
+     *	edisplay_c side methods
+     */
+    void draw ()
+    {
+      if (menu)
+      {
+	menu->draw ();
+	menu_disp = menu;
+      }
+    }
+
+    void undraw ()
+    {
+      if (menu_disp)
+	{
+	  menu_disp->undraw ();
+	  //menu_disp = 0;
+	}
+    }
+
+    int can_undraw ()
+    {
+      if (menu_disp)
+	return menu_disp->can_undraw ();
+      else
+	return 1;
+    }
+
+    int need_to_clear ()
+    {
+      if (menu_disp)
+	return menu_disp->need_to_clear ();
+      else
+	return 0;
+    }
+
+    void clear ()
+    {
+      if (menu_disp)
+	menu_disp->clear ();
+    }
+
+  private :
+
+    Menu *menu;
+    Menu *menu_disp;
+};
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/mouse.cc	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,219 @@
+/*
+ *	mouse.cc
+ *	DOS mouse interface
+ *	RQ sometime in 1993 or 1994.
+ */
+
+
+/*
+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"
+
+
+#ifdef Y_BGI
+
+#include <dos.h>
+
+/* mouse interrupt number */
+#define MOUSE 0x33
+
+/* the global data */
+bool UseMouse;			/* is there a mouse driver? */
+
+
+/*
+   initialize the mouse driver
+*/
+
+void CheckMouseDriver (void)
+{
+union  REGS  regs;
+struct SREGS sregs;
+
+regs.x.ax = 0x0000;
+int86(MOUSE, &regs, &regs);
+if (regs.x.ax == 0xffff)
+   {
+   UseMouse = true; /* mouse */
+#if defined Y_BGI && defined CIRRUS_PATCH
+   /*
+      note from RQ:
+	 This test is temporary and should be removed in DEU 5.3
+	 We should create a better "fake cursor" by using the
+	 mouse callback function.  Remember to remove the callback
+	 when DEU exits...
+   */
+   if (CirrusCursor)
+      {
+      regs.x.ax = 0x000C;
+      regs.x.cx = 0x0001;
+      regs.x.dx = FP_OFF (MouseCallBackFunction);
+      sregs.es  = FP_SEG (MouseCallBackFunction);
+      int86x (MOUSE, &regs, &regs, &sregs);
+      }
+#endif /* Y_BGI && CIRRUS_PATCH */
+#ifdef AYM_MOUSE_HACKS
+   regs.x.ax = 0x001b;
+   int86x (MOUSE, &regs, &regs, &sregs);
+   LogMessage ("Mouse: h=%d v=%d\n", regs.x.bx, regs.x.cx);
+   regs.x.ax = 0x000f;
+   regs.x.cx = MouseMickeysH;
+   regs.x.dx = MouseMickeysV;
+   int86x (MOUSE, &regs, &regs, &sregs);
+#endif  /* AYM_MOUSE_HACKS */
+   }
+else
+UseMouse = false; /* no mouse */
+}
+
+
+/*
+   show the pointer
+*/
+
+void ShowMousePointer (void)
+{
+union REGS regs;
+
+if (UseMouse)
+   {
+   regs.x.ax = 0x0001;
+   int86(MOUSE, &regs, &regs);
+   }
+}
+
+
+/*
+   hide the pointer
+*/
+
+void HideMousePointer (void)
+{
+union REGS regs;
+
+if (UseMouse)
+   {
+   regs.x.ax = 0x0002;
+   int86(MOUSE, &regs, &regs);
+   }
+}
+
+
+/*
+   read pointer coordinates
+*/
+
+void GetMouseCoords (int *x, int *y, int *buttons)
+{
+static int oldx = 42, oldy = 42;
+union REGS regs;
+
+regs.x.ax = 0x0003;
+int86(MOUSE, &regs, &regs);
+if (x != NULL)
+   *x = regs.x.cx;
+if (y != NULL)
+   *y = regs.x.dx;
+if (buttons != NULL)
+   *buttons = regs.x.bx;
+if (*x != oldx || *y != oldy)
+   {
+   LogMessage ("Mouse %5d %5d\n", *x, *y);
+   oldx = *x;
+   oldy = *y;
+   }
+}
+
+
+
+/*
+   change pointer coordinates
+*/
+
+void SetMouseCoords (int x, int y)
+{
+union REGS regs;
+
+regs.x.ax = 0x0004;
+regs.x.cx = (unsigned) x;
+regs.x.dx = (unsigned) y;
+int86(MOUSE, &regs, &regs);
+}
+
+
+
+/*
+   set horizontal and vertical limits (constrain pointer in a box)
+*/
+
+void SetMouseLimits( int x0, int y0, int x1, int y1)
+{
+union REGS regs;
+
+regs.x.ax = 0x0007;
+regs.x.cx = (unsigned) x0;
+regs.x.dx = (unsigned) x1;
+int86(MOUSE, &regs, &regs);
+regs.x.ax = 0x0008;
+regs.x.cx = (unsigned) y0;
+regs.x.dx = (unsigned) y1;
+int86(MOUSE, &regs, &regs);
+}
+
+
+
+/*
+   reset horizontal and vertical limits
+*/
+
+void ResetMouseLimits (void)
+{
+union REGS regs;
+
+regs.x.ax = 0x0007;
+regs.x.cx = (unsigned) 0;
+regs.x.dx = (unsigned) ScrMaxX;
+int86(MOUSE, &regs, &regs);
+regs.x.ax = 0x0008;
+regs.x.cx = (unsigned) 0;
+regs.x.dx = (unsigned) ScrMaxY;
+int86(MOUSE, &regs, &regs);
+}
+
+
+
+/*
+   mouse callback function
+*/
+
+void MouseCallBackFunction (void)
+{
+#if defined Y_BGI && defined CIRRUS_PATCH
+if (CirrusCursor)
+   SetHWCursorPos(_CX, _DX);
+#endif /* Y_BGI && CIRRUS_PATCH */
+}
+#endif  /* #ifdef Y_BGI */
+
+/* end of file */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/names.cc	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,232 @@
+/*
+ *	names.cc
+ *	BW & RQ sometime in 1993 or 1994.
+ */
+
+
+/*
+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 "game.h"
+#include "objid.h"
+
+
+/*
+   get the name of an object type
+*/
+const char *GetObjectTypeName (int objtype)
+{
+switch (objtype)
+   {
+   case OBJ_THINGS:   return "thing";
+   case OBJ_LINEDEFS: return "linedef";
+   case OBJ_SIDEDEFS: return "sidedef";
+   case OBJ_VERTICES: return "vertex";
+   case OBJ_SEGS:     return "segment";
+   case OBJ_SSECTORS: return "ssector";
+   case OBJ_NODES:    return "node";
+   case OBJ_SECTORS:  return "sector";
+   case OBJ_REJECT:   return "reject";
+   case OBJ_BLOCKMAP: return "blockmap";
+   }
+return "< Bug! >";
+}
+
+
+
+/*
+   what are we editing?
+*/
+const char *GetEditModeName (int objtype)
+{
+switch (objtype)
+   {
+   case OBJ_THINGS:   return "Things";
+   case OBJ_LINEDEFS:
+   case OBJ_SIDEDEFS: return "LD & SD";
+   case OBJ_VERTICES: return "Vertices";
+   case OBJ_SEGS:     return "Segments";
+   case OBJ_SSECTORS: return "Seg-Sectors";
+   case OBJ_NODES:    return "Nodes";
+   case OBJ_SECTORS:  return "Sectors";
+   }
+return "< Bug! >";
+}
+
+
+
+/*
+   get a short (16 char.) description of the type of a linedef
+*/
+
+const char *GetLineDefTypeName (int type)
+{
+if (CUR_LDTDEF != NULL && CUR_LDTDEF->number == type)
+  return CUR_LDTDEF->shortdesc;
+for (al_lrewind (ldtdef); ! al_leol (ldtdef); al_lstep (ldtdef))
+  if (CUR_LDTDEF->number == type)
+    return CUR_LDTDEF->shortdesc;
+return "??  UNKNOWN";
+}
+
+
+/*
+   get a short description of the flags of a linedef
+*/
+
+const char *GetLineDefFlagsName (int flags)
+{
+static char buf[20];
+// "P" is a Boom extension ("pass through")
+// "T" is for Strife ("translucent")
+const char *flag_chars = "???T??PANBSLU2MI";
+int n;
+
+char *p = buf;
+for (n = 0; n < 16; n++)
+   {
+   if (n != 0 && n % 4 == 0)
+      *p++ = ' ';
+   if (flags & (0x8000u >> n))
+      *p++ = flag_chars[n];
+   else
+      *p++ = '-';
+   }
+*p = '\0';
+return buf;
+
+#if 0
+static char temp[20];
+if (flags & 0x0100)
+   strcpy (temp, "A"); /* Already on the map (Ma) */
+else
+   strcpy (temp, "-");
+if (flags & 0x80)
+   strcat (temp, "V"); /* Invisible on the map (In) */
+else
+   strcat (temp, "-");
+if (flags & 0x40)
+   strcat (temp, "B"); /* Blocks sound (So) */
+else
+   strcat (temp, "-");
+if (flags & 0x20)
+   strcat (temp, "S"); /* Secret (normal on the map) (Se) */
+else
+   strcat (temp, "-");
+if (flags & 0x10)
+   strcat (temp, "L"); /* Lower texture offset changed (Lo) */
+else
+   strcat (temp, "-");
+if (flags & 0x08)
+   strcat (temp, "U"); /* Upper texture offset changed (Up) */
+else
+   strcat (temp, "-");
+if (flags & 0x04)
+   strcat (temp, "2"); /* Two-sided (2S) */
+else
+   strcat (temp, "-");
+if (flags & 0x02)
+   strcat (temp, "M"); /* Monsters can't cross this line (Mo) */
+else
+   strcat (temp, "-");
+if (flags & 0x01)
+   strcat (temp, "I"); /* Impassible (Im) */
+else
+   strcat (temp, "-");
+if (strlen (temp) > 13)
+{
+   temp[13] = '|';
+   temp[14] = '\0';
+}
+return temp;
+#endif
+}
+
+
+
+/*
+   get a long description of one linedef flag
+*/
+
+const char *GetLineDefFlagsLongName (int flags)
+{
+if (flags & 0x1000) return "Translucent [Strife]";
+if (flags & 0x200)  return "Pass-through [Boom]";
+if (flags & 0x100)  return "Always shown on the map";
+if (flags & 0x80)   return "Never shown on the map";
+if (flags & 0x40)   return "Blocks sound";
+if (flags & 0x20)   return "Secret (shown as normal on the map)";
+if (flags & 0x10)   return "Lower texture is \"unpegged\"";
+if (flags & 0x08)   return "Upper texture is \"unpegged\"";
+if (flags & 0x04)   return "Two-sided (may be transparent)";
+if (flags & 0x02)   return "Monsters cannot cross this line";
+if (flags & 0x01)   return "Impassible";
+return "UNKNOWN";
+}
+
+
+
+/*
+   get a short (14 char.) description of the type of a sector
+*/
+
+const char *GetSectorTypeName (int type)
+{
+/* KLUDGE: To avoid the last element which is bogus */
+if (al_ltell (stdef) == al_lcount (stdef) - 1)
+  al_lrewind (stdef);
+
+if (CUR_STDEF != NULL && CUR_STDEF->number == type)
+  return CUR_STDEF->shortdesc;
+for (al_lrewind (stdef); ! al_leol (stdef); al_lstep (stdef))
+  if (CUR_STDEF->number == type)
+    return CUR_STDEF->shortdesc;
+static char buf[30];
+sprintf (buf, "UNKNOWN (%d)", type);
+return buf;
+}
+
+
+
+/*
+   get a long description of the type of a sector
+*/
+
+const char *GetSectorTypeLongName (int type)
+{
+/* KLUDGE: To avoid the last element which is bogus */
+if (al_ltell (stdef) == al_lcount (stdef) - 1)
+  al_lrewind (stdef);
+
+if (CUR_STDEF != NULL && CUR_STDEF->number == type)
+  return CUR_STDEF->longdesc;
+for (al_lrewind (stdef); ! al_leol (stdef); al_lstep (stdef))
+  if (CUR_STDEF->number == type)
+    return CUR_STDEF->longdesc;
+static char buf[30];
+sprintf (buf, "UNKNOWN (%d)", type);
+return buf;
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/nop.cc	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,37 @@
+/*
+ *	nop.cc
+ *	AYM 1998-06-??
+ */
+
+
+/*
+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"
+
+
+void nop (...)
+{
+;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/objects.cc	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,1228 @@
+/*
+ *	objects.cc
+ *	Object handling routines.
+ *	BW & RQ sometime in 1993 or 1994.
+ */
+
+
+/*
+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 "drawmap.h"
+#include "gfx.h"
+#include "l_vertices.h"
+#include "levels.h"
+#include "objects.h"
+#include "objid.h"
+#include "s_vertices.h"
+#include "selectn.h"
+#include "things.h"
+
+
+/*
+   highlight the selected objects
+*/
+void HighlightSelection (int objtype, SelPtr list) /* SWAP! */
+{
+SelPtr cur;
+
+if (! list)
+   return;
+for (cur = list; cur; cur = cur->next)
+   HighlightObject (objtype, cur->objnum, GREEN);
+}
+
+
+
+/*
+   get the number of objects of a given type minus one
+*/
+obj_no_t GetMaxObjectNum (int objtype)
+{
+switch (objtype)
+   {
+   case OBJ_THINGS:
+      return NumThings - 1;
+   case OBJ_LINEDEFS:
+      return NumLineDefs - 1;
+   case OBJ_SIDEDEFS:
+      return NumSideDefs - 1;
+   case OBJ_VERTICES:
+      return NumVertices - 1;
+   case OBJ_SECTORS:
+      return NumSectors - 1;
+   }
+return -1;
+}
+
+
+/*
+   highlight the selected object
+*/
+void HighlightObject (int objtype, int objnum, int colour) /* SWAP! */
+{
+int  n, m;
+
+/* use XOR mode : drawing any line twice erases it */
+SetDrawingMode (1);
+set_colour (colour);
+switch (objtype)
+   {
+   case OBJ_THINGS:
+      ObjectsNeeded (OBJ_THINGS, 0);
+      m = (get_thing_radius (Things[objnum].type) * 3) / 2;
+      DrawMapLine (Things[objnum].xpos - m, Things[objnum].ypos - m,
+		   Things[objnum].xpos - m, Things[objnum].ypos + m);
+      DrawMapLine (Things[objnum].xpos - m, Things[objnum].ypos + m,
+		   Things[objnum].xpos + m, Things[objnum].ypos + m);
+      DrawMapLine (Things[objnum].xpos + m, Things[objnum].ypos + m,
+		   Things[objnum].xpos + m, Things[objnum].ypos - m);
+      DrawMapLine (Things[objnum].xpos + m, Things[objnum].ypos - m,
+		   Things[objnum].xpos - m, Things[objnum].ypos - m);
+      DrawMapArrow (Things[objnum].xpos, Things[objnum].ypos,
+		    Things[objnum].angle * 182);
+      break;
+
+   case OBJ_LINEDEFS:
+      ObjectsNeeded (OBJ_LINEDEFS, OBJ_VERTICES, 0);
+      n = (Vertices[LineDefs[objnum].start].x
+	 + Vertices[LineDefs[objnum].end].x) / 2;
+      m = (Vertices[LineDefs[objnum].start].y
+	 + Vertices[LineDefs[objnum].end].y) / 2;
+      DrawMapLine (n, m, n + (Vertices[LineDefs[objnum].end].y
+			    - Vertices[LineDefs[objnum].start].y) / 3,
+			 m + (Vertices[LineDefs[objnum].start].x
+			    - Vertices[LineDefs[objnum].end].x) / 3);
+      SetLineThickness (1);
+      DrawMapVector (Vertices[LineDefs[objnum].start].x,
+		     Vertices[LineDefs[objnum].start].y,
+		     Vertices[LineDefs[objnum].end].x,
+		     Vertices[LineDefs[objnum].end].y);
+      if (colour != LIGHTRED && LineDefs[objnum].tag > 0)
+	 {
+	 for (m = 0; m < NumSectors; m++)
+	    if (Sectors[m].tag == LineDefs[objnum].tag)
+	       HighlightObject (OBJ_SECTORS, m, LIGHTRED);
+	 }
+      SetLineThickness (0);
+      break;
+
+   case OBJ_VERTICES:
+      ObjectsNeeded (OBJ_VERTICES, 0);
+      {
+      int r = vertex_radius (Scale) * 3 / 2;
+      int scrx0 = SCREENX (Vertices[objnum].x) - r;
+      int scrx9 = SCREENX (Vertices[objnum].x) + r;
+      int scry0 = SCREENY (Vertices[objnum].y) - r;
+      int scry9 = SCREENY (Vertices[objnum].y) + r;
+      DrawScreenLine (scrx0, scry0, scrx9, scry0);
+      DrawScreenLine (scrx9, scry0, scrx9, scry9);
+      DrawScreenLine (scrx9, scry9, scrx0, scry9);
+      DrawScreenLine (scrx0, scry9, scrx0, scry0);
+      }
+      break;
+
+   case OBJ_SECTORS:
+      {
+      ObjectsNeeded (OBJ_LINEDEFS, OBJ_SIDEDEFS, OBJ_VERTICES, 0);
+      SetLineThickness (1);
+      const int mapx0 = MAPX (0);
+      const int mapy0 = MAPY (ScrMaxY);
+      const int mapx1 = MAPX (ScrMaxX);
+      const int mapy1 = MAPY (0);
+      for (n = 0; n < NumLineDefs; n++)
+	 if (LineDefs[n].sidedef1 != -1
+	     && SideDefs[LineDefs[n].sidedef1].sector == objnum
+	  || LineDefs[n].sidedef2 != -1
+	     && SideDefs[LineDefs[n].sidedef2].sector == objnum)
+	 {
+	    const struct Vertex *v1 = Vertices + LineDefs[n].start;
+	    const struct Vertex *v2 = Vertices + LineDefs[n].end;
+	    if (v1->x < mapx0 && v2->x < mapx0
+	     || v1->x > mapx1 && v2->x > mapx1
+	     || v1->y < mapy0 && v2->y < mapy0
+	     || v1->y > mapy1 && v2->y > mapy1)
+	       continue;  // Off-screen
+	    DrawMapLine (v1->x, v1->y, v2->x, v2->y);
+	 }
+      if (colour != LIGHTRED && Sectors[objnum].tag > 0)
+	 {
+	 for (m = 0; m < NumLineDefs; m++)
+	    if (LineDefs[m].tag == Sectors[objnum].tag)
+	       HighlightObject (OBJ_LINEDEFS, m, LIGHTRED);
+	 }
+      SetLineThickness (0);
+      }
+      break;
+   }
+/* restore normal write mode */
+SetDrawingMode (0);
+}
+
+
+
+/*
+   delete an object
+*/
+void DeleteObject (const Objid& obj) /* SWAP! */
+{
+SelPtr list;
+
+list = 0;
+SelectObject (&list, obj.num);
+DeleteObjects (obj.type, &list);
+}
+
+
+
+/*
+   delete a group of objects (*recursive*)
+*/
+void DeleteObjects (int objtype, SelPtr *list) /* SWAP! */
+{
+int    n, objnum;
+SelPtr cur;
+
+MadeChanges = 1;
+switch (objtype)
+   {
+   case OBJ_THINGS:
+      ObjectsNeeded (OBJ_THINGS, 0);
+      if (*list)
+	 {
+	 things_angles++;
+	 things_types++;
+	 }
+      while (*list)
+	 {
+	 objnum = (*list)->objnum;
+	 if (objnum < 0 || objnum >= NumThings)  // Paranoia
+	 {
+	    nf_bug ("attempt to delete non-existent thing #%d", objnum);
+	    goto next_thing;
+	 }
+	 // Delete the thing
+	 NumThings--;
+	 if (NumThings > 0)
+	    {
+	    for (n = objnum; n < NumThings; n++)
+	       Things[n] = Things[n + 1];
+	    Things = (TPtr) ResizeFarMemory (Things,
+	       NumThings * sizeof (struct Thing));
+	    }
+	 else
+	    {
+	    FreeFarMemory (Things);
+	    Things = 0;
+	    }
+	 for (cur = (*list)->next; cur; cur = cur->next)
+	    if (cur->objnum > objnum)
+	       cur->objnum--;
+	 next_thing:
+	 UnSelectObject (list, objnum);
+	 }
+      break;
+
+   case OBJ_VERTICES:
+      if (*list)
+         MadeMapChanges = 1;
+      while (*list)
+	 {
+	 objnum = (*list)->objnum;
+	 if (objnum < 0 || objnum >= NumVertices)  // Paranoia
+	 {
+	    nf_bug ("attempt to delete non-existent vertex #%d", objnum);
+	    goto next_vertex;
+	 }
+	 // Delete the linedefs bound to this vertex and change the references
+	 ObjectsNeeded (OBJ_LINEDEFS, 0);
+	 for (n = 0; n < NumLineDefs; n++)
+	    {
+	    if (LineDefs[n].start == objnum || LineDefs[n].end == objnum)
+	       DeleteObject (Objid (OBJ_LINEDEFS, n--));
+	    else
+	       {
+	       if (LineDefs[n].start >= objnum)
+		  LineDefs[n].start--;
+	       if (LineDefs[n].end >= objnum)
+		  LineDefs[n].end--;
+	       }
+	    }
+	 // Delete the vertex
+	 ObjectsNeeded (OBJ_VERTICES, 0);
+	 NumVertices--;
+	 if (NumVertices > 0)
+	    {
+	    for (n = objnum; n < NumVertices; n++)
+	       Vertices[n] = Vertices[n + 1];
+	    Vertices = (VPtr) ResizeFarMemory (Vertices,
+	      NumVertices * sizeof (struct Vertex));
+	    }
+	 else
+	    {
+	    FreeFarMemory (Vertices);
+	    Vertices = 0;
+	    }
+	 for (cur = (*list)->next; cur; cur = cur->next)
+	    if (cur->objnum > objnum)
+	       cur->objnum--;
+	 next_vertex:
+	 UnSelectObject (list, objnum);
+	 }
+      break;
+
+   case OBJ_LINEDEFS:
+      /* In DEU, deleting a linedef was not considered to be a
+	 map change. Deleting a _sidedef_ was. In Yadex,
+	 sidedefs are not automatically deleted when the linedef
+	 is because some sidedefs are shared by more than one
+	 linedef. So we need to set MadeMapChanges here. */
+      if (*list)
+         MadeMapChanges = 1;
+      /* AYM 19980203 I've removed the deletion of sidedefs
+         because if several linedefs use the same sidedef, this
+         would lead to trouble. Instead, I let the xref checking
+         take care of that. */
+      while (*list)
+	 {
+	 ObjectsNeeded (OBJ_LINEDEFS, 0);
+	 objnum = (*list)->objnum;
+	 if (objnum < 0 || objnum >= NumLineDefs)  // Paranoia
+	 {
+	    nf_bug ("attempt to delete non-existent linedef #%d", objnum);
+	    goto next_linedef;
+	 }
+	 // delete the linedef
+	 NumLineDefs--;
+	 if (NumLineDefs > 0)
+	    {
+	    for (n = objnum; n < NumLineDefs; n++)
+	       LineDefs[n] = LineDefs[n + 1];
+	    LineDefs = (LDPtr) ResizeFarMemory (LineDefs,
+	      NumLineDefs * sizeof (struct LineDef));
+	    }
+	 else
+	    {
+	    FreeFarMemory (LineDefs);
+	    LineDefs = 0;
+	    }
+	 for (cur = (*list)->next; cur; cur = cur->next)
+	    if (cur->objnum > objnum)
+	       cur->objnum--;
+	 next_linedef:
+	 UnSelectObject (list, objnum);
+	 }
+      break;
+
+   case OBJ_SIDEDEFS:
+      if (*list)
+         MadeMapChanges = 1;
+      while (*list)
+	 {
+	 objnum = (*list)->objnum;
+	 if (objnum < 0 || objnum >= NumSideDefs)  // Paranoia
+	 {
+	    nf_bug ("attempt to delete non-existent sidedef #%d", objnum);
+	    goto next_sidedef;
+	 }
+	 /* change the linedefs references */
+	 ObjectsNeeded (OBJ_LINEDEFS, 0);
+	 for (n = 0; n < NumLineDefs; n++)
+	    {
+	    if (LineDefs[n].sidedef1 == objnum)
+	       LineDefs[n].sidedef1 = -1;
+	    else if (LineDefs[n].sidedef1 >= objnum)
+	       LineDefs[n].sidedef1--;
+	    if (LineDefs[n].sidedef2 == objnum)
+	       LineDefs[n].sidedef2 = -1;
+	    else if (LineDefs[n].sidedef2 >= objnum)
+	       LineDefs[n].sidedef2--;
+	    }
+	 /* delete the sidedef */
+	 ObjectsNeeded (OBJ_SIDEDEFS, 0);
+	 NumSideDefs--;
+	 if (NumSideDefs > 0)
+	    {
+	    for (n = objnum; n < NumSideDefs; n++)
+	       SideDefs[n] = SideDefs[n + 1];
+	    SideDefs = (SDPtr) ResizeFarMemory (SideDefs,
+	       NumSideDefs * sizeof (struct SideDef));
+	    }
+	 else
+	    {
+	    FreeFarMemory (SideDefs);
+	    SideDefs = 0;
+	    }
+	 for (cur = (*list)->next; cur; cur = cur->next)
+	    if (cur->objnum > objnum)
+	       cur->objnum--;
+	 next_sidedef:
+	 UnSelectObject (list, objnum);
+	 }
+      break;
+   case OBJ_SECTORS:
+      while (*list)
+	{
+	objnum = (*list)->objnum;
+	 if (objnum < 0 || objnum >= NumSectors)  // Paranoia
+	 {
+	    nf_bug ("attempt to delete non-existent sector #%d", objnum);
+	    goto next_sector;
+	 }
+	// Delete the sidedefs bound to this sector and change the references
+	// AYM 19980203: Hmm, hope this is OK with multiply used sidedefs...
+	ObjectsNeeded (OBJ_SIDEDEFS, 0);
+	for (n = 0; n < NumSideDefs; n++)
+	   if (SideDefs[n].sector == objnum)
+	      DeleteObject (Objid (OBJ_SIDEDEFS, n--));
+	   else if (SideDefs[n].sector >= objnum)
+	      SideDefs[n].sector--;
+	/* delete the sector */
+	ObjectsNeeded (OBJ_SECTORS, 0);
+	NumSectors--;
+	if (NumSectors > 0)
+	   {
+	   for (n = objnum; n < NumSectors; n++)
+	      Sectors[n] = Sectors[n + 1];
+	   Sectors = (SPtr) ResizeFarMemory (Sectors,
+	      NumSectors * sizeof (struct Sector));
+	   }
+	else
+	   {
+	   FreeFarMemory (Sectors);
+	   Sectors = 0;
+	   }
+	for (cur = (*list)->next; cur; cur = cur->next)
+	   if (cur->objnum > objnum)
+	      cur->objnum--;
+	next_sector:
+	UnSelectObject (list, objnum);
+	}
+      break;
+   default:
+      nf_bug ("DeleteObjects: bad objtype %d", (int) objtype);
+   }
+}
+
+
+
+/*
+ *	InsertObject
+ *	Insert a new object of type <objtype> at map coordinates
+ *	(<xpos>, <ypos>).
+ *
+ *	If <copyfrom> is a valid object number, the other properties
+ *	of the new object are set from the properties of that object,
+ *	with the exception of sidedef numbers, which are forced
+ *	to OBJ_NO_NONE.
+ *
+ *	The object is inserted at the exact coordinates given.
+ *	No snapping to grid is done.
+ */
+void InsertObject (obj_type_t objtype, obj_no_t copyfrom, int xpos, int ypos)
+								/* SWAP! */
+{
+int last;
+
+ObjectsNeeded (objtype, 0);
+MadeChanges = 1;
+switch (objtype)
+   {
+   case OBJ_THINGS:
+      last = NumThings++;
+      if (last > 0)
+	 Things = (TPtr) ResizeFarMemory (Things,
+	   (unsigned long) NumThings * sizeof (struct Thing));
+      else
+	 Things = (TPtr) GetFarMemory (sizeof (struct Thing));
+      Things[last].xpos = xpos;
+      Things[last].ypos = ypos;
+      things_angles++;
+      things_types++;
+      if (is_obj (copyfrom))
+	 {
+	 Things[last].type  = Things[copyfrom].type;
+	 Things[last].angle = Things[copyfrom].angle;
+	 Things[last].when  = Things[copyfrom].when;
+	 }
+      else
+	 {
+	 Things[last].type = default_thing;
+	 Things[last].angle = 0;
+	 Things[last].when  = 0x07;
+	 }
+      break;
+
+   case OBJ_VERTICES:
+      last = NumVertices++;
+      if (last > 0)
+	 Vertices = (VPtr) ResizeFarMemory (Vertices,
+	   (unsigned long) NumVertices * sizeof (struct Vertex));
+      else
+	 Vertices = (VPtr) GetFarMemory (sizeof (struct Vertex));
+      Vertices[last].x = xpos;
+      Vertices[last].y = ypos;
+      if (Vertices[last].x < MapMinX)
+	 MapMinX = Vertices[last].x;
+      if (Vertices[last].x > MapMaxX)
+	 MapMaxX = Vertices[last].x;
+      if (Vertices[last].y < MapMinY)
+	 MapMinY = Vertices[last].y;
+      if (Vertices[last].y > MapMaxY)
+	 MapMaxY = Vertices[last].y;
+      MadeMapChanges = 1;
+      break;
+
+   case OBJ_LINEDEFS:
+      last = NumLineDefs++;
+      if (last > 0)
+	 LineDefs = (LDPtr) ResizeFarMemory (LineDefs,
+	   (unsigned long) NumLineDefs * sizeof (struct LineDef));
+      else
+	 LineDefs = (LDPtr) GetFarMemory (sizeof (struct LineDef));
+      if (is_obj (copyfrom))
+	 {
+	 LineDefs[last].start = LineDefs[copyfrom].start;
+	 LineDefs[last].end   = LineDefs[copyfrom].end;
+	 LineDefs[last].flags = LineDefs[copyfrom].flags;
+	 LineDefs[last].type  = LineDefs[copyfrom].type;
+	 LineDefs[last].tag   = LineDefs[copyfrom].tag;
+	 }
+      else
+	 {
+	 LineDefs[last].start = 0;
+	 LineDefs[last].end   = NumVertices - 1;
+	 LineDefs[last].flags = 1;
+	 LineDefs[last].type  = 0;
+	 LineDefs[last].tag   = 0;
+	 }
+      LineDefs[last].sidedef1 = OBJ_NO_NONE;
+      LineDefs[last].sidedef2 = OBJ_NO_NONE;
+      break;
+
+   case OBJ_SIDEDEFS:
+      last = NumSideDefs++;
+      if (last > 0)
+	 SideDefs = (SDPtr) ResizeFarMemory (SideDefs,
+	   (unsigned long) NumSideDefs * sizeof (struct SideDef));
+      else
+	 SideDefs = (SDPtr) GetFarMemory (sizeof (struct SideDef));
+      if (is_obj (copyfrom))
+	 {
+	 SideDefs[last].xoff = SideDefs[copyfrom].xoff;
+	 SideDefs[last].yoff = SideDefs[copyfrom].yoff;
+	 strncpy (SideDefs[last].tex1, SideDefs[copyfrom].tex1, WAD_TEX_NAME);
+	 strncpy (SideDefs[last].tex2, SideDefs[copyfrom].tex2, WAD_TEX_NAME);
+	 strncpy (SideDefs[last].tex3, SideDefs[copyfrom].tex3, WAD_TEX_NAME);
+	 SideDefs[last].sector = SideDefs[copyfrom].sector;
+	 }
+      else
+	 {
+	 SideDefs[last].xoff = 0;
+	 SideDefs[last].yoff = 0;
+	 strcpy (SideDefs[last].tex1, "-");
+	 strcpy (SideDefs[last].tex2, "-");
+	 strcpy (SideDefs[last].tex3, default_middle_texture);
+	 SideDefs[last].sector = NumSectors - 1;
+	 }
+      MadeMapChanges = 1;
+      break;
+
+   case OBJ_SECTORS:
+      last = NumSectors++;
+      if (last > 0)
+	 Sectors = (SPtr) ResizeFarMemory (Sectors,
+			  (unsigned long) NumSectors * sizeof (struct Sector));
+      else
+	 Sectors = (SPtr) GetFarMemory (sizeof (struct Sector));
+      if (is_obj (copyfrom))
+	 {
+	 Sectors[last].floorh  = Sectors[copyfrom].floorh;
+	 Sectors[last].ceilh   = Sectors[copyfrom].ceilh;
+	 strncpy (Sectors[last].floort, Sectors[copyfrom].floort, WAD_FLAT_NAME);
+	 strncpy (Sectors[last].ceilt, Sectors[copyfrom].ceilt, WAD_FLAT_NAME);
+	 Sectors[last].light   = Sectors[copyfrom].light;
+	 Sectors[last].special = Sectors[copyfrom].special;
+	 Sectors[last].tag     = Sectors[copyfrom].tag;
+	 }
+      else
+	 {
+	 Sectors[last].floorh  = default_floor_height;
+	 Sectors[last].ceilh   = default_ceiling_height;
+	 strncpy (Sectors[last].floort, default_floor_texture, WAD_FLAT_NAME);
+	 strncpy (Sectors[last].ceilt, default_ceiling_texture, WAD_FLAT_NAME);
+	 Sectors[last].light   = default_light_level;
+	 Sectors[last].special = 0;
+	 Sectors[last].tag     = 0;
+	 }
+      break;
+
+   default:
+      nf_bug ("InsertObject: bad objtype %d", (int) objtype);
+   }
+}
+
+
+
+/*
+   check if a (part of a) LineDef is inside a given block
+*/
+bool IsLineDefInside (int ldnum, int x0, int y0, int x1, int y1) /* SWAP - needs Vertices & LineDefs */
+{
+int lx0 = Vertices[LineDefs[ldnum].start].x;
+int ly0 = Vertices[LineDefs[ldnum].start].y;
+int lx1 = Vertices[LineDefs[ldnum].end].x;
+int ly1 = Vertices[LineDefs[ldnum].end].y;
+int i;
+
+/* do you like mathematics? */
+if (lx0 >= x0 && lx0 <= x1 && ly0 >= y0 && ly0 <= y1)
+   return 1; /* the linedef start is entirely inside the square */
+if (lx1 >= x0 && lx1 <= x1 && ly1 >= y0 && ly1 <= y1)
+   return 1; /* the linedef end is entirely inside the square */
+if ((ly0 > y0) != (ly1 > y0))
+   {
+   i = lx0 + (int) ((long) (y0 - ly0) * (long) (lx1 - lx0) / (long) (ly1 - ly0));
+   if (i >= x0 && i <= x1)
+      return true; /* the linedef crosses the y0 side (left) */
+   }
+if ((ly0 > y1) != (ly1 > y1))
+   {
+   i = lx0 + (int) ((long) (y1 - ly0) * (long) (lx1 - lx0) / (long) (ly1 - ly0));
+   if (i >= x0 && i <= x1)
+      return true; /* the linedef crosses the y1 side (right) */
+   }
+if ((lx0 > x0) != (lx1 > x0))
+   {
+   i = ly0 + (int) ((long) (x0 - lx0) * (long) (ly1 - ly0) / (long) (lx1 - lx0));
+   if (i >= y0 && i <= y1)
+      return true; /* the linedef crosses the x0 side (down) */
+   }
+if ((lx0 > x1) != (lx1 > x1))
+   {
+   i = ly0 + (int) ((long) (x1 - lx0) * (long) (ly1 - ly0) / (long) (lx1 - lx0));
+   if (i >= y0 && i <= y1)
+      return true; /* the linedef crosses the x1 side (up) */
+   }
+return false;
+}
+
+
+
+/*
+   get the sector number of the sidedef opposite to this sidedef
+   (returns -1 if it cannot be found)
+*/
+int GetOppositeSector (int ld1, bool firstside) /* SWAP! */
+{
+int x0, y0, dx0, dy0;
+int x1, y1, dx1, dy1;
+int x2, y2, dx2, dy2;
+int ld2, dist;
+int bestld, bestdist, bestmdist;
+
+/* get the coords for this LineDef */
+ObjectsNeeded (OBJ_LINEDEFS, OBJ_VERTICES, 0);
+x0  = Vertices[LineDefs[ld1].start].x;
+y0  = Vertices[LineDefs[ld1].start].y;
+dx0 = Vertices[LineDefs[ld1].end].x - x0;
+dy0 = Vertices[LineDefs[ld1].end].y - y0;
+
+/* find the normal vector for this LineDef */
+x1  = (dx0 + x0 + x0) / 2;
+y1  = (dy0 + y0 + y0) / 2;
+if (firstside)
+   {
+   dx1 = dy0;
+   dy1 = -dx0;
+   }
+else
+   {
+   dx1 = -dy0;
+   dy1 = dx0;
+   }
+
+bestld = -1;
+/* use a parallel to an axis instead of the normal vector (faster method) */
+if (abs (dy1) > abs (dx1))
+   {
+   if (dy1 > 0)
+      {
+      /* get the nearest LineDef in that direction (increasing Y's: North) */
+      bestdist = 32767;
+      bestmdist = 32767;
+      for (ld2 = 0; ld2 < NumLineDefs; ld2++)
+	 if (ld2 != ld1 && ((Vertices[LineDefs[ld2].start].x > x1)
+			 != (Vertices[LineDefs[ld2].end].x > x1)))
+	    {
+	    x2  = Vertices[LineDefs[ld2].start].x;
+	    y2  = Vertices[LineDefs[ld2].start].y;
+	    dx2 = Vertices[LineDefs[ld2].end].x - x2;
+	    dy2 = Vertices[LineDefs[ld2].end].y - y2;
+	    dist = y2 + (int) ((long) (x1 - x2) * (long) dy2 / (long) dx2);
+	    if (dist > y1 && (dist < bestdist
+	     || (dist == bestdist && (y2 + dy2 / 2) < bestmdist)))
+	       {
+	       bestld = ld2;
+	       bestdist = dist;
+	       bestmdist = y2 + dy2 / 2;
+	       }
+	    }
+      }
+   else
+      {
+      /* get the nearest LineDef in that direction (decreasing Y's: South) */
+      bestdist = -32767;
+      bestmdist = -32767;
+      for (ld2 = 0; ld2 < NumLineDefs; ld2++)
+	 if (ld2 != ld1 && ((Vertices[LineDefs[ld2].start].x > x1)
+			 != (Vertices[LineDefs[ld2].end].x > x1)))
+	    {
+	    x2  = Vertices[LineDefs[ld2].start].x;
+	    y2  = Vertices[LineDefs[ld2].start].y;
+	    dx2 = Vertices[LineDefs[ld2].end].x - x2;
+	    dy2 = Vertices[LineDefs[ld2].end].y - y2;
+	    dist = y2 + (int) ((long) (x1 - x2) * (long) dy2 / (long) dx2);
+	    if (dist < y1 && (dist > bestdist
+	     || (dist == bestdist && (y2 + dy2 / 2) > bestmdist)))
+	       {
+	       bestld = ld2;
+	       bestdist = dist;
+	       bestmdist = y2 + dy2 / 2;
+	       }
+	    }
+      }
+   }
+else
+   {
+   if (dx1 > 0)
+      {
+      /* get the nearest LineDef in that direction (increasing X's: East) */
+      bestdist = 32767;
+      bestmdist = 32767;
+      for (ld2 = 0; ld2 < NumLineDefs; ld2++)
+	 if (ld2 != ld1 && ((Vertices[LineDefs[ld2].start].y > y1)
+			 != (Vertices[LineDefs[ld2].end].y > y1)))
+	    {
+	    x2  = Vertices[LineDefs[ld2].start].x;
+	    y2  = Vertices[LineDefs[ld2].start].y;
+	    dx2 = Vertices[LineDefs[ld2].end].x - x2;
+	    dy2 = Vertices[LineDefs[ld2].end].y - y2;
+	    dist = x2 + (int) ((long) (y1 - y2) * (long) dx2 / (long) dy2);
+	    if (dist > x1 && (dist < bestdist
+	     || (dist == bestdist && (x2 + dx2 / 2) < bestmdist)))
+	       {
+	       bestld = ld2;
+	       bestdist = dist;
+	       bestmdist = x2 + dx2 / 2;
+	       }
+	    }
+      }
+   else
+      {
+      /* get the nearest LineDef in that direction (decreasing X's: West) */
+      bestdist = -32767;
+      bestmdist = -32767;
+      for (ld2 = 0; ld2 < NumLineDefs; ld2++)
+	 if (ld2 != ld1 && ((Vertices[LineDefs[ld2].start].y > y1)
+			 != (Vertices[LineDefs[ld2].end].y > y1)))
+	    {
+	    x2  = Vertices[LineDefs[ld2].start].x;
+	    y2  = Vertices[LineDefs[ld2].start].y;
+	    dx2 = Vertices[LineDefs[ld2].end].x - x2;
+	    dy2 = Vertices[LineDefs[ld2].end].y - y2;
+	    dist = x2 + (int) ((long) (y1 - y2) * (long) dx2 / (long) dy2);
+	    if (dist < x1 && (dist > bestdist
+	     || (dist == bestdist && (x2 + dx2 / 2) > bestmdist)))
+	       {
+	       bestld = ld2;
+	       bestdist = dist;
+	       bestmdist = x2 + dx2 / 2;
+	       }
+	    }
+      }
+   }
+
+/* no intersection: the LineDef was pointing outwards! */
+if (bestld < 0)
+   return -1;
+
+/* now look if this LineDef has a SideDef bound to one sector */
+if (abs (dy1) > abs (dx1))
+   {
+   if ((Vertices[LineDefs[bestld].start].x
+	< Vertices[LineDefs[bestld].end].x) == (dy1 > 0))
+      x0 = LineDefs[bestld].sidedef1;
+   else
+      x0 = LineDefs[bestld].sidedef2;
+   }
+else
+   {
+   if ((Vertices[LineDefs[bestld].start].y
+      < Vertices[LineDefs[bestld].end].y) != (dx1 > 0))
+      x0 = LineDefs[bestld].sidedef1;
+   else
+      x0 = LineDefs[bestld].sidedef2;
+   }
+
+/* there is no SideDef on this side of the LineDef! */
+if (x0 < 0)
+   return -1;
+
+/* OK, we got it -- return the Sector number */
+ObjectsNeeded (OBJ_SIDEDEFS, 0);
+return SideDefs[x0].sector;
+}
+
+
+
+/*
+   copy a group of objects to a new position
+*/
+void CopyObjects (int objtype, SelPtr obj) /* SWAP! */
+{
+int        n, m;
+SelPtr     cur;
+SelPtr     list1, list2;
+SelPtr     ref1, ref2;
+
+if (! obj)
+   return;
+ObjectsNeeded (objtype, 0);
+/* copy the object(s) */
+switch (objtype)
+   {
+   case OBJ_THINGS:
+      for (cur = obj; cur; cur = cur->next)
+	 {
+	 InsertObject (OBJ_THINGS, cur->objnum, Things[cur->objnum].xpos,
+						Things[cur->objnum].ypos);
+	 cur->objnum = NumThings - 1;
+	 }
+      MadeChanges = 1;
+      break;
+
+   case OBJ_VERTICES:
+      for (cur = obj; cur; cur = cur->next)
+	 {
+	 InsertObject (OBJ_VERTICES, cur->objnum, Vertices[cur->objnum].x,
+						  Vertices[cur->objnum].y);
+	 cur->objnum = NumVertices - 1;
+	 }
+      MadeChanges = 1;
+      MadeMapChanges = 1;
+      break;
+
+   case OBJ_LINEDEFS:
+      list1 = 0;
+      list2 = 0;
+
+      // Create the linedefs and maybe the sidedefs
+      for (cur = obj; cur; cur = cur->next)
+	 {
+         int old = cur->objnum;	// No. of original linedef
+         int New;		// No. of duplicate linedef
+
+	 InsertObject (OBJ_LINEDEFS, old, 0, 0);
+         New = NumLineDefs - 1;
+
+         if (copy_linedef_reuse_sidedefs)
+	    {
+	    /* AYM 1997-07-25: not very orthodox (the New linedef and 
+	       the old one use the same sidedefs). but, in the case where
+	       you're copying into the same sector, it's much better than
+	       having to create the New sidedefs manually. plus it saves
+	       space in the .wad and also it makes editing easier (editing
+	       one sidedef impacts all linedefs that use it). */
+	    LineDefs[New].sidedef1 = LineDefs[old].sidedef1; 
+	    LineDefs[New].sidedef2 = LineDefs[old].sidedef2; 
+	    }
+         else
+            {
+            /* AYM 1998-11-08: duplicate sidedefs too.
+               DEU 5.21 just left the sidedef references to -1. */
+            if (is_sidedef (LineDefs[old].sidedef1))
+	       {
+	       InsertObject (OBJ_SIDEDEFS, LineDefs[old].sidedef1, 0, 0);
+	       LineDefs[New].sidedef1 = NumSideDefs - 1;
+	       }
+            if (is_sidedef (LineDefs[old].sidedef2))
+	       {
+	       InsertObject (OBJ_SIDEDEFS, LineDefs[old].sidedef2, 0, 0);
+	       LineDefs[New].sidedef2 = NumSideDefs - 1; 
+	       }
+            }
+	 cur->objnum = New;
+	 if (!IsSelected (list1, LineDefs[New].start))
+	    {
+	    SelectObject (&list1, LineDefs[New].start);
+	    SelectObject (&list2, LineDefs[New].start);
+	    }
+	 if (!IsSelected (list1, LineDefs[New].end))
+	    {
+	    SelectObject (&list1, LineDefs[New].end);
+	    SelectObject (&list2, LineDefs[New].end);
+	    }
+	 }
+
+      // Create the vertices
+      CopyObjects (OBJ_VERTICES, list2);
+      ObjectsNeeded (OBJ_LINEDEFS, 0);
+
+      // Update the references to the vertices
+      for (ref1 = list1, ref2 = list2;
+	   ref1 && ref2;
+	   ref1 = ref1->next, ref2 = ref2->next)
+	 {
+	 for (cur = obj; cur; cur = cur->next)
+	    {
+	    if (ref1->objnum == LineDefs[cur->objnum].start)
+	      LineDefs[cur->objnum].start = ref2->objnum;
+	    if (ref1->objnum == LineDefs[cur->objnum].end)
+	      LineDefs[cur->objnum].end = ref2->objnum;
+	    }
+	 }
+      ForgetSelection (&list1);
+      ForgetSelection (&list2);
+      break;
+
+   case OBJ_SECTORS:
+      ObjectsNeeded (OBJ_LINEDEFS, OBJ_SIDEDEFS, 0);
+      list1 = 0;
+      list2 = 0;
+      // Create the linedefs (and vertices)
+      for (cur = obj; cur; cur = cur->next)
+	 {
+	 for (n = 0; n < NumLineDefs; n++)
+	    if  ((((m = LineDefs[n].sidedef1) >= 0
+		       && SideDefs[m].sector == cur->objnum)
+		|| ((m = LineDefs[n].sidedef2) >= 0
+		       && SideDefs[m].sector == cur->objnum))
+		       && ! IsSelected (list1, n))
+	       {
+	       SelectObject (&list1, n);
+	       SelectObject (&list2, n);
+	       }
+	 }
+      CopyObjects (OBJ_LINEDEFS, list2);
+      /* create the sidedefs */
+      ObjectsNeeded (OBJ_LINEDEFS, 0);
+      for (ref1 = list1, ref2 = list2;
+	   ref1 && ref2;
+	   ref1 = ref1->next, ref2 = ref2->next)
+	 {
+	 if ((n = LineDefs[ref1->objnum].sidedef1) >= 0)
+	    {
+	    InsertObject (OBJ_SIDEDEFS, n, 0, 0);
+	    n = NumSideDefs - 1;
+	    ObjectsNeeded (OBJ_LINEDEFS, 0);
+	    LineDefs[ref2->objnum].sidedef1 = n;
+	    }
+	 if ((m = LineDefs[ref1->objnum].sidedef2) >= 0)
+	    {
+	    InsertObject (OBJ_SIDEDEFS, m, 0, 0);
+	    m = NumSideDefs - 1;
+	    ObjectsNeeded (OBJ_LINEDEFS, 0);
+	    LineDefs[ref2->objnum].sidedef2 = m;
+	    }
+	 ref1->objnum = n;
+	 ref2->objnum = m;
+	 }
+      /* create the Sectors */
+      for (cur = obj; cur; cur = cur->next)
+	 {
+	 InsertObject (OBJ_SECTORS, cur->objnum, 0, 0);
+	 ObjectsNeeded (OBJ_SIDEDEFS, 0);
+	 for (ref1 = list1, ref2 = list2;
+	      ref1 && ref2;
+	      ref1 = ref1->next, ref2 = ref2->next)
+	    {
+	    if (ref1->objnum >= 0
+               && SideDefs[ref1->objnum].sector == cur->objnum)
+	       SideDefs[ref1->objnum].sector = NumSectors - 1;
+	    if (ref2->objnum >= 0
+               && SideDefs[ref2->objnum].sector == cur->objnum)
+	       SideDefs[ref2->objnum].sector = NumSectors - 1;
+	    }
+	 cur->objnum = NumSectors - 1;
+	 }
+      ForgetSelection (&list1);
+      ForgetSelection (&list2);
+      break;
+   }
+}
+
+
+
+/*
+ *	MoveObjectsToCoords
+ *	Move a group of objects to a new position
+ *
+ *	You must first call it with obj == NULL and newx and newy
+ *	set to the coordinates of the reference point (E.G. the
+ *	object being dragged).
+ *	Then, every time the object being dragged has changed its
+ *	coordinates, call the it again with newx and newy set to
+ *	the new position and obj set to the selection.
+ *
+ *	Returns <>0 iff an object was moved.
+ */
+bool MoveObjectsToCoords (
+   int objtype,
+   SelPtr obj,
+   int newx,
+   int newy,
+   int grid) /* SWAP! */
+{
+int        dx, dy;
+SelPtr     cur, vertices;
+static int refx, refy; /* previous position */
+
+ObjectsNeeded (objtype, 0);
+if (grid > 0)
+   {
+   newx = (newx + grid / 2) & ~(grid - 1);
+   newy = (newy + grid / 2) & ~(grid - 1);
+   }
+
+// Only update the reference point ?
+if (! obj)
+   {
+   refx = newx;
+   refy = newy;
+   return true;
+   }
+
+/* compute the displacement */
+dx = newx - refx;
+dy = newy - refy;
+/* nothing to do? */
+if (dx == 0 && dy == 0)
+   return false;
+
+/* move the object(s) */
+switch (objtype)
+   {
+   case OBJ_THINGS:
+      for (cur = obj; cur; cur = cur->next)
+	 {
+	 Things[cur->objnum].xpos += dx;
+	 Things[cur->objnum].ypos += dy;
+	 }
+      refx = newx;
+      refy = newy;
+      MadeChanges = 1;
+      break;
+
+   case OBJ_VERTICES:
+      for (cur = obj; cur; cur = cur->next)
+	 {
+	 Vertices[cur->objnum].x += dx;
+	 Vertices[cur->objnum].y += dy;
+	 }
+      refx = newx;
+      refy = newy;
+      MadeChanges = 1;
+      MadeMapChanges = 1;
+      break;
+
+   case OBJ_LINEDEFS:
+      vertices = list_vertices_of_linedefs (obj);
+      MoveObjectsToCoords (OBJ_VERTICES, vertices, newx, newy, grid);
+      ForgetSelection (&vertices);
+      break;
+
+   case OBJ_SECTORS:
+      ObjectsNeeded (OBJ_LINEDEFS, OBJ_SIDEDEFS, 0);
+      vertices = list_vertices_of_sectors (obj);
+      MoveObjectsToCoords (OBJ_VERTICES, vertices, newx, newy, grid);
+      ForgetSelection (&vertices);
+      break;
+   }
+return true;
+}
+
+
+
+/*
+   get the coordinates (approx.) of an object
+*/
+void GetObjectCoords (int objtype, int objnum, int *xpos, int *ypos) /* SWAP! */
+{
+int  n, v1, v2, sd1, sd2;
+long accx, accy, num;
+
+switch (objtype)
+   {
+   case OBJ_THINGS:
+      if (! is_thing (objnum))		// Can't happen
+	 {
+	 nf_bug ("GetObjectCoords: bad thing# %d", objnum);
+	 *xpos = 0;
+	 *ypos = 0;
+	 return;
+	 }
+      ObjectsNeeded (OBJ_THINGS, 0);
+      *xpos = Things[objnum].xpos;
+      *ypos = Things[objnum].ypos;
+      break;
+
+   case OBJ_VERTICES:
+      if (! is_vertex (objnum))		// Can't happen
+	 {
+	 nf_bug ("GetObjectCoords: bad vertex# %d", objnum);
+	 *xpos = 0;
+	 *ypos = 0;
+	 return;
+	 }
+      ObjectsNeeded (OBJ_VERTICES, 0);
+      *xpos = Vertices[objnum].x;
+      *ypos = Vertices[objnum].y;
+      break;
+
+   case OBJ_LINEDEFS:
+      if (! is_linedef (objnum))	// Can't happen
+	 {
+	 nf_bug ("GetObjectCoords: bad linedef# %d", objnum);
+	 *xpos = 0;
+	 *ypos = 0;
+	 return;
+	 }
+      ObjectsNeeded (OBJ_LINEDEFS, 0);
+      v1 = LineDefs[objnum].start;
+      v2 = LineDefs[objnum].end;
+      ObjectsNeeded (OBJ_VERTICES, 0);
+      *xpos = (Vertices[v1].x + Vertices[v2].x) / 2;
+      *ypos = (Vertices[v1].y + Vertices[v2].y) / 2;
+      break;
+
+   case OBJ_SIDEDEFS:
+      if (! is_sidedef (objnum))	// Can't happen
+	 {
+	 nf_bug ("GetObjectCoords: bad sidedef# %d", objnum);
+	 *xpos = 0;
+	 *ypos = 0;
+	 return;
+	 }
+      ObjectsNeeded (OBJ_LINEDEFS, 0);
+      for (n = 0; n < NumLineDefs; n++)
+	 if (LineDefs[n].sidedef1 == objnum || LineDefs[n].sidedef2 == objnum)
+	    {
+	    v1 = LineDefs[n].start;
+	    v2 = LineDefs[n].end;
+	    ObjectsNeeded (OBJ_VERTICES, 0);
+	    *xpos = (Vertices[v1].x + Vertices[v2].x) / 2;
+	    *ypos = (Vertices[v1].y + Vertices[v2].y) / 2;
+	    return;
+	    }
+      *xpos = (MapMinX + MapMaxX) / 2;
+      *ypos = (MapMinY + MapMaxY) / 2;
+      // FIXME is the fall through intentional ? -- AYM 2000-11-08
+
+   case OBJ_SECTORS:
+      if (! is_sector (objnum))		// Can't happen
+	 {
+	 nf_bug ("GetObjectCoords: bad sector# %d", objnum);
+	 *xpos = 0;
+	 *ypos = 0;
+	 return;
+	 }
+      accx = 0L;
+      accy = 0L;
+      num = 0L;
+      for (n = 0; n < NumLineDefs; n++)
+	 {
+	 ObjectsNeeded (OBJ_LINEDEFS, 0);
+	 sd1 = LineDefs[n].sidedef1;
+	 sd2 = LineDefs[n].sidedef2;
+	 v1 = LineDefs[n].start;
+	 v2 = LineDefs[n].end;
+	 ObjectsNeeded (OBJ_SIDEDEFS, 0);
+	 if ((sd1 >= 0 && SideDefs[sd1].sector == objnum)
+	       || (sd2 >= 0 && SideDefs[sd2].sector == objnum))
+	    {
+	    ObjectsNeeded (OBJ_VERTICES, 0);
+	    /* if the Sector is closed, all Vertices will be counted twice */
+	    accx += (long) Vertices[v1].x;
+	    accy += (long) Vertices[v1].y;
+	    num++;
+	    accx += (long) Vertices[v2].x;
+	    accy += (long) Vertices[v2].y;
+	    num++;
+	    }
+	 }
+      if (num > 0)
+	 {
+	 *xpos = (int) ((accx + num / 2L) / num);
+	 *ypos = (int) ((accy + num / 2L) / num);
+	 }
+      else
+	 {
+	 *xpos = (MapMinX + MapMaxX) / 2;
+	 *ypos = (MapMinY + MapMaxY) / 2;
+	 }
+      break;
+
+   default:
+      nf_bug ("GetObjectCoords: bad objtype %d", objtype);  // Can't happen
+      *xpos = 0;
+      *ypos = 0;
+   }
+}
+
+
+
+/*
+   find a free tag number
+*/
+int FindFreeTag () /* SWAP! */
+{
+int  tag, n;
+bool ok;
+
+ObjectsNeeded (OBJ_LINEDEFS, OBJ_SECTORS, 0);
+tag = 1;
+ok = false;
+while (! ok)
+   {
+   ok = true;
+   for (n = 0; n < NumLineDefs; n++)
+      if (LineDefs[n].tag == tag)
+	 {
+	 ok = false;
+	 break;
+	 }
+   if (ok)
+      for (n = 0; n < NumSectors; n++)
+	 if (Sectors[n].tag == tag)
+	    {
+	    ok = false;
+	    break;
+	    }
+   tag++;
+   }
+return tag - 1;
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/objects.h	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,30 @@
+/*
+ *	objects.h
+ *	AYM 2000-11-06
+ */
+
+
+#ifndef YH_OBJECTS  /* DO NOT INSERT ANYTHING BEFORE THIS LINE */
+#define YH_OBJECTS
+
+
+#include "objid.h"
+
+
+void	HighlightSelection (int, SelPtr);
+obj_no_t GetMaxObjectNum (int);
+void	GetCurObject (Objid& o, int objtype, int x, int y);
+void	SelectObjectsInBox (SelPtr *list, int, int, int, int, int);
+void	HighlightObject (int, int, int);
+void	DeleteObject (const Objid&);
+void	DeleteObjects (int, SelPtr *);
+void	InsertObject (obj_type_t, obj_no_t, int, int);
+bool	IsLineDefInside (int, int, int, int, int);
+int	GetOppositeSector (int, bool);
+void	CopyObjects (int, SelPtr);
+bool	MoveObjectsToCoords (int, SelPtr, int, int, int);
+void	GetObjectCoords (int, int, int *, int *);
+int	FindFreeTag (void);
+
+
+#endif  /* DO NOT ADD ANYTHING AFTER THIS LINE */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/objid.h	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,83 @@
+/*
+ *	objid.h - object identity class
+ *	AYM 2000-11-06
+ */
+
+
+/*
+This file is part of Atclib.
+
+Atclib is Copyright © 1995-1999 André Majorel.
+
+This library is free software; you can redistribute it and/or modify it under
+the terms of the GNU Library General Public License as published by the Free
+Software Foundation; either version 2 of the License, or (at your option) any
+later version.
+
+This library 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 Library General Public License for more
+details.
+
+You should have received a copy of the GNU Library General Public License
+along with this library; if not, write to the Free Software Foundation, Inc.,
+59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+
+#ifndef YH_OBJID  /* DO NOT INSERT ANYTHING BEFORE THIS LINE */
+#define YH_OBJID
+
+
+// FIXME turn those #defines to consts
+// FIXME there is an ambiguity in this class. Does canvas count
+// as an object or not ? The issue could use some thought.
+
+// Object types
+#define OBJ_NONE	0
+#define OBJ_THINGS	1
+#define OBJ_LINEDEFS	2
+#define OBJ_SIDEDEFS	3
+#define OBJ_VERTICES	4
+#define OBJ_SEGS	5
+#define OBJ_SSECTORS	6
+#define OBJ_NODES	7
+#define OBJ_SECTORS	8
+#define OBJ_REJECT	9
+#define OBJ_BLOCKMAP	10
+#define OBJ_ANY		11
+
+// Special object numbers
+typedef i16  obj_no_t;
+typedef char obj_type_t;
+#define OBJ_NO_NONE    -1
+#define OBJ_NO_CANVAS  -2
+#define is_obj(n)      ((n) >= 0)
+#define is_linedef(n)  ((n) >= 0 && (n) < NumLineDefs)
+#define is_sector(n)   ((n) >= 0 && (n) < NumSectors )
+#define is_sidedef(n)  ((n) >= 0 && (n) < NumSideDefs)
+#define is_thing(n)    ((n) >= 0 && (n) < NumThings  )
+#define is_vertex(n)   ((n) >= 0 && (n) < NumVertices)
+
+class Objid
+{
+  public :
+    Objid () { num = -1; type = OBJ_NONE; }
+    Objid (obj_type_t t, obj_no_t n) { type = t; num = n; }
+    bool operator== (const Objid& other) const
+    {
+      return other.type == type && other.num == num;
+    }
+    bool _is_linedef () const { return type == OBJ_LINEDEFS && num >= 0; }
+    bool _is_sector  () const { return type == OBJ_SECTORS  && num >= 0; }
+    bool _is_thing   () const { return type == OBJ_THINGS   && num >= 0; }
+    bool _is_vertex  () const { return type == OBJ_VERTICES && num >= 0; }
+    bool is_nil     () const { return num <  0 || type == OBJ_NONE; }
+    bool operator() () const { return num >= 0 && type != OBJ_NONE; } 
+    void nil () { num = -1; type = OBJ_NONE; }
+    obj_type_t type;
+    obj_no_t   num;
+};
+
+
+#endif  /* DO NOT ADD ANYTHING AFTER THIS LINE */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/objinfo.cc	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,792 @@
+/*
+ *	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;
+
+  ObjectsNeeded (obj_type, 0);
+  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));
+	ObjectsNeeded (OBJ_SIDEDEFS, OBJ_SECTORS, 0);
+	{
+	  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);
+	ObjectsNeeded (OBJ_VERTICES, 0);
+	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;
+
+	ObjectsNeeded (OBJ_LINEDEFS, 0);
+	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);
+	  ObjectsNeeded (OBJ_LINEDEFS, 0);
+	  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 ());
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/objinfo.h	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,80 @@
+/*
+ *	objinfo.h
+ *	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 "edwidget.h"
+
+
+class objinfo_c : public edwidget_c
+   {
+   public :
+      objinfo_c ();
+      void set (int obj_type, int obj_no)
+      {
+        this->obj_no   = obj_no;
+	this->obj_type = obj_type;
+      }
+
+      void set_y1 (int y1)
+	 { out_y1 = y1; }
+
+      /* Methods declared in edwidget_c */
+      void unset ()
+	 { obj_no = OBJ_NO_NONE; }
+
+      void draw ();
+
+      void undraw ()
+         { }  // Sorry, I don't know how to undraw myself
+
+      int can_undraw ()
+         { return 0; }  // I don't have the ability to undraw myself
+
+      int need_to_clear ()
+	 { return is_obj (obj_no_disp) && ! is_obj (obj_no); }
+
+      void clear ()
+      {
+	for (size_t n = 0; n < MAX_BOXES; n++)
+	  box_disp[n] = false;
+	obj_no_disp = OBJ_NO_NONE;
+      }
+
+   private :
+      static const size_t MAX_BOXES = 10;
+      bool box_disp[MAX_BOXES];	// Is the box already drawn ?
+      int obj_no;        // The no. of the object we should display info about
+      int obj_type;      // The type of the object we should display info about
+      int obj_no_disp;	 // The no. and type of the object for which info
+      int obj_type_disp; // is really displayed.
+      int prev_sector;   // No. of the last sector for which info was displayed
+      int prev_floorh;   // Its floor height.
+      int prev_ceilh;    // Its ceiling height.
+      int out_y1;        // The bottom outer edge of the info window.
+   };
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/oldmenus.cc	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,167 @@
+/*
+ *	oldmenus.cc
+ *	Old-fashioned menu functions, somewhat similar to the
+ *	ones DEU 5.21 had in menus.c. Since they contain an event
+ *	loop of their own, they can't handle expose and configure
+ *	notify events properly. When I have the time, I'll
+ *	replace this system by a modal widgets stack in
+ *	edisplay.cc.
+ *	AYM 1998-12-03
+ */
+
+
+/*
+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 <X11/Xlib.h>
+#include "events.h"
+#include "gfx.h"
+#include "menu.h"
+#include "oldmenus.h"
+
+
+static int loop (Menu *menu, int x, int y, int item_no);
+
+
+/*
+ *	vDisplayMenu - create a menu from variable arguments and call loop()
+ *
+ *	Display and execute a popup menu defined with variable
+ *	arguments.
+ *
+ *	Return the same thing as Menu::process_event().
+ */
+int vDisplayMenu (int x0, int y0, const char *title, ...)
+{
+  va_list args;
+
+  va_start (args, title);
+  Menu menu (title, args);
+  va_end (args);
+  int r = loop (&menu, x0, y0, 0);
+  return r + 1;
+}
+
+
+/*
+ *	DisplayMenuList - create a menu from a list and call loop()
+ *
+ *	Display and execute a menu contained in a list. Each
+ *	menu item string is obtained by calling (*getstr)() with
+ *	a pointer on the list item.
+ *
+ *	Return the number of the selected item (0-based) or -1
+ *	if exited by [Esc].
+ *
+ *	This function is deprecated.
+ */
+int DisplayMenuList (
+  int		x0,
+  int		y0,
+  const char	*menutitle,
+  al_llist_t	*list,
+  const char	*(*getstr)(void *),
+  int		*item_no)
+{
+  Menu menu (menutitle, list, getstr);
+  int r = loop (&menu, x0, y0, item_no ? *item_no : 0);
+  if (item_no && r >= 0)
+    *item_no = r;
+  return r;
+}
+
+
+/*
+ *	DisplayMenuList - create a menu from a Menu_data and call loop()
+ *
+ *	Display and execute a menu contained in a Menu_data.
+ *
+ *	Return the number of the selected item (0-based) or -1
+ *	if exited by [Esc].
+ *
+ *	This function is deprecated.
+ */
+int DisplayMenuList (
+  int		x0,
+  int		y0,
+  const char	*menutitle,
+  Menu_data&    menudata,
+  int		*item_no)
+{
+  Menu menu (menutitle, menudata);
+  int r = loop (&menu, x0, y0, item_no ? *item_no : 0);
+  if (item_no && r >= 0)
+    *item_no = r;
+  return r;
+}
+
+
+/*
+ *	loop - display and execute a menu
+ *
+ *	Return the number of the selected item (0-based) or -1
+ *	if exited by [Esc].
+ *
+ *	This function is nothing more than a quick and dirty
+ *	hack, provided as a stopgap until the widget stack is
+ *	implemented and the code uses it. 
+ */
+static int loop (Menu *menu, int x, int y, int item_no)
+{
+  menu->set_popup         (true);
+  menu->set_force_numbers (true);
+  menu->set_coords        (x, y);
+  menu->set_visible       (true);
+  menu->set_item_no       (item_no);
+  for (;;)
+  {
+    menu->draw ();
+    if (has_event ())
+    {
+      is.key = get_event ();
+      // If we had called get_input_status(), XNextEvent()
+      // would have been called and we wouldn't have to do that.
+      XFlush (dpy);
+    }
+    else
+      get_input_status ();
+    if (is.key == YE_EXPOSE)
+      menu->clear ();  // Force menu to redraw itself from scratch
+    else if (is.key == YE_BUTL_PRESS
+      && ((int) is.x < menu->get_x0 ()
+	 || (int) is.x > menu->get_x1 ()
+	 || (int) is.y < menu->get_y0 ()
+	 || (int) is.y > menu->get_y1 ()))
+      return -1;
+    else
+    {
+      int r = menu->process_event (&is);
+      if (r == MEN_CANCEL)
+	 return -1;
+      else if (r >= 0)
+	 return r;
+    }
+  }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/oldmenus.h	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,32 @@
+/*
+ *	oldmenus.h
+ *	AYM 1998-12-04
+ */
+
+
+#ifndef YH_OLDMENUS  /* DO NOT INSERT ANYTHING BEFORE THIS LINE */
+#define YH_OLDMENUS
+
+
+class Menu_data;
+
+
+int vDisplayMenu (int, int, const char *, ...);
+
+int DisplayMenuList (
+   int		x0,
+   int		y0,
+   const char	*title,
+   al_llist_t	*list,
+   const char	*(*getstr)(void *),
+   int		*item_no);
+
+int DisplayMenuList (
+  int		x0,
+  int		y0,
+  const char	*menutitle,
+  Menu_data&    menudata,
+  int		*item_no);
+
+
+#endif  /* DO NOT ADD ANYTHING AFTER THIS LINE */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/palview.cc	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,433 @@
+/*
+ *	palview.cc
+ *	Palette (PLAYPAL & COLORMAP) viewer
+ *	AYM 1999-11-11
+ */
+
+
+/*
+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 <X11/Xlib.h>
+#include "colour.h"
+#include "gcolour2.h"
+#include "gfx.h"
+#include "palview.h"
+#include "rgb.h"
+#include "wadfile.h"
+#include "wads.h"
+#include "ytime.h"
+
+
+/*
+ *	Palette viewer::run
+ *	The only public method of the palette viewer.
+ */
+
+// One COLORMAP entry. Wrapped in struct to avoid array<->pointer problems
+typedef struct { u8 c[DOOM_COLOURS]; } colormap_entry_t;
+
+void Palette_viewer::run ()
+{
+int       lines    = (ncolours + columns - 1) / columns;
+const int pwidth   = columns * (pixels + 1);
+const int pheight  = lines * (pixels + 1);
+int       width    = 2 * BOX_BORDER + 2 * WIDE_HSPACING + pwidth;
+int       height   = 2 * BOX_BORDER + 3 * WIDE_VSPACING + pheight + 7 * FONTH;
+int       x0       = (ScrMaxX - width) / 2;
+int       y0       = (ScrMaxY - height) / 2;
+int       nmaps    = 0;  // Number of entries in the COLORMAP lump
+colormap_entry_t **colormap = 0;
+rgb_c    *playpal  = 0;
+
+// Load the PLAYPAL lump
+do
+{
+  playpal = new rgb_c[DOOM_COLOURS];
+  for (size_t n = 0; n < DOOM_COLOURS; n++)
+    playpal[n].set (0, 0, 0);
+  const char *lump_name = "PLAYPAL";
+  MDirPtr dir = FindMasterDir (MasterDir, lump_name);
+  if (dir == NULL)
+  {
+    warn ("%s: lump not found\n", lump_name);
+    break;
+  }
+  const Wad_file *wf = dir->wadfile;
+  if (dir->dir.size % (3 * DOOM_COLOURS) != 0)
+  {
+    warn ("%s has weird size (%ld, not mult of %d), ignoring tail\n",
+      lump_name, (long) dir->dir.size, (int) (DOOM_COLOURS * 3));
+  }
+  wf->seek (dir->dir.start);
+  if (wf->error ())
+  {
+    warn ("%s: seek error\n", lump_name);
+    break;
+  }
+  playpal = new rgb_c[DOOM_COLOURS];
+  for (size_t n = 0; n < DOOM_COLOURS; n++)
+  {
+    char buf[3];
+    wf->read_bytes (buf, sizeof buf);
+    playpal[n].set (buf[0], buf[1], buf[2]);
+  }
+  if (wf->error ())
+    warn ("%s: read error\n", lump_name);
+}
+while (0);
+
+// Load the COLORMAP lump
+do
+{
+  const char *lump_name = "COLORMAP";
+  MDirPtr dir = FindMasterDir (MasterDir, lump_name);
+  if (dir == NULL)
+  {
+    warn ("%s: lump not found\n", lump_name);
+    break;
+  }
+  const Wad_file *wf = dir->wadfile;
+  nmaps = dir->dir.size / DOOM_COLOURS;
+  if ((long) DOOM_COLOURS * nmaps != dir->dir.size)
+  {
+    warn ("%s: has weird size (%ld, not mult of %d), ignoring tail\n",
+      lump_name, (long) dir->dir.size, (int) DOOM_COLOURS);
+  }
+  if (nmaps > 200)
+  {
+    warn ("%s has too many (%d) entries, keeping only 200 first\n",
+	lump_name, nmaps);
+    nmaps = 200;
+  }
+  wf->seek (dir->dir.start);
+  if (wf->error ())
+  {
+    warn ("%s: seek error\n", lump_name);
+    break;
+  }
+  colormap = new colormap_entry_t *[nmaps];
+  for (int n = 0; n < nmaps; n++)
+  {
+    colormap[n] = new colormap_entry_t;
+    wf->read_bytes (colormap[n]->c, sizeof colormap[n]->c);
+  }
+  if (wf->error ())
+    warn ("%s: read error\n", lump_name);
+}
+while (0);
+
+// On to the real business
+ix0 = x0 + BOX_BORDER + WIDE_HSPACING;
+iy0 = y0 + BOX_BORDER + WIDE_VSPACING;
+int tx0 = ix0;					// Top left corner of text
+int ty0 = y0 + BOX_BORDER + 2 * WIDE_VSPACING + pheight;
+push_colour (0);				// Save current colour
+#define DECIDX(i,n) do { i = (i - n + ncolours) % ncolours; } while (0)
+#define INCIDX(i,n) do { i = (i + n           ) % ncolours; } while (0)
+int           mapno         = 0;
+bool          mapping       = true;
+int           is_drawn      = 0;
+const int     YID_WINDOW    = 0x01;
+const int     YID_CURSOR    = 0x02;
+const int     YID_PALETTE   = 0x04;
+const int     YID_TEXT      = 0x08;
+int           cursor_phase  = 0;
+int           display_phase = 0;
+unsigned long cursor_time   = 0;
+i   = 0;
+ofs = 0;
+
+for (;;)
+{
+  int mi = colormap[mapno]->c[i];	// Mapped index
+  int ei = mapping ? mi : i;		// Effective index
+  int mapped_to = 0;			// N. distinct colours that map to i
+  for (int n = 0; n < ncolours; n++)
+    for (int m = 0; m < nmaps; m++)
+      if (colormap[m]->c[n] == i)
+      {
+	mapped_to++;
+	break;        // Don't count the same mapper twice
+      }
+  int maps_to = 0;			// N. distinct colours that i maps to
+  {
+    bitvec_c mappee (ncolours);
+    for (int m = 0; m < nmaps; m++)
+      mappee.set (colormap[m]->c[i]);
+    for (int n = 0; n < ncolours; n++)
+      if (mappee.get (n))
+	maps_to++;
+  }
+
+  // Draw the window
+  if (! (is_drawn & YID_WINDOW))
+  {
+    DrawScreenBox3D (x0, y0, x0 + width - 1, y0 + height - 1);
+    is_drawn = YID_WINDOW;  // Redraw everything else
+  }
+
+  // Draw the cursor (frame around the current cell)
+  {
+    const int cycle = 800;  // 800 ms
+    unsigned long current_time = y_milliseconds ();
+    unsigned long elapsed_time = current_time - cursor_time;
+    cursor_time = current_time;
+#if 0
+    cursor_time += elapsed_time - elapsed_time % cycle;  // Normalize
+    elapsed_time = current_time - cursor_time;
+#endif
+    cursor_phase = (cursor_phase + elapsed_time) % cycle;
+    if ((cursor_phase >= cycle / 2) != (display_phase >= cycle / 2))
+      is_drawn &= ~YID_CURSOR;
+    if (! (is_drawn & YID_CURSOR))
+    {
+      draw_cursor (WINFG, cursor_phase >= cycle / 2);
+      display_phase = cursor_phase;
+      is_drawn |= YID_CURSOR;
+    }
+  }
+
+  // Draw a (pixels x pixels) square for each colour
+  if (! (is_drawn & YID_PALETTE))
+  {
+    int x = 0;  // Initialized only to prevent GCC from warning
+    int y = 0;  // Initialized only to prevent GCC from warning
+    for (int n = 0; n < ncolours; n++)
+    {
+      if (n % columns == 0)
+      {
+	x = ix0;
+	if (n == 0)
+	  y = iy0;
+	else
+	  y += pixels + 1;
+      }
+      else
+	x += pixels + 1;
+
+      if (game_colour == 0)  // If PLAYPAL not found
+	set_pcolour (0);
+      else
+      {
+	if (mapping)
+	  set_pcolour (game_colour[colormap[mapno]->c[(n + ofs) % ncolours]]);
+	else
+	  set_pcolour (game_colour[(n + ofs) % ncolours]);
+      }
+      DrawScreenBoxwh (x, y, pixels, pixels);
+    }
+    is_drawn |= YID_PALETTE;
+    set_colour (WINFG_DIM);  // Just to force the next set_colour() to do sth
+  }
+
+  // Draw the "caption"
+  if (! (is_drawn & YID_TEXT))
+  {
+    set_colour (WINBG);
+    DrawScreenBoxwh (tx0, ty0, pwidth, 7 * FONTH);
+    set_colour (WINFG);
+    DrawScreenText (tx0, ty0, "Index        %3d", i);
+    push_colour (mapping ? WINFG : WINFG_DIM);
+    DrawScreenText (tx0, -1,  "Mapped index %3d", mi);
+    pop_colour ();
+    DrawScreenText (tx0, -1,  "R            %3d", playpal[ei].r);
+    DrawScreenText (tx0, -1,  "G            %3d", playpal[ei].g);
+    DrawScreenText (tx0, -1,  "B            %3d", playpal[ei].b);
+    DrawScreenText (tx0, -1,  "Mapped to by %3d", mapped_to);
+    DrawScreenText (tx0, -1,  "Maps to      %3d", maps_to);
+    push_colour (mapping ? WINFG : WINFG_DIM);
+    DrawScreenText (tx0 + 18 * FONTW, ty0, "Colormap %3d", mapno);
+    pop_colour ();
+    is_drawn |= YID_TEXT;
+  }
+
+  // Process any events
+  get_input_status ();
+  if (is.key == YK_PU)			// [Pgup] previous colormap
+  {
+    mapno--;
+    if (mapno < 0)
+      mapno = nmaps - 1;
+    is_drawn &= ~(YID_PALETTE | YID_TEXT);
+  }
+  else if (is.key == YK_PD)		// [Pgdn] next colormap
+  {
+    mapno++;
+    if (mapno >= nmaps)
+      mapno = 0;
+    is_drawn &= ~(YID_PALETTE | YID_TEXT);
+  }
+  else if (is.key == YK_LEFT)		// [Left] previous palette entry
+  {
+    draw_cursor (WINBG, false);
+    DECIDX (i, 1);
+    is_drawn &= ~(YID_PALETTE | YID_TEXT | YID_CURSOR);
+    cursor_phase = 0;
+  }
+  else if (is.key == YK_RIGHT)		// [Right] next palette entry
+  {
+    draw_cursor (WINBG, false);
+    INCIDX (i, 1);
+    is_drawn &= ~(YID_TEXT | YID_CURSOR);
+    cursor_phase = 0;
+  }
+  else if (is.key == YK_UP)		// [Up] previous palette row
+  {
+    draw_cursor (WINBG, false);
+    DECIDX (i, columns);
+    is_drawn &= ~(YID_TEXT | YID_CURSOR);
+    cursor_phase = 0;
+  }
+  else if (is.key == YK_DOWN)		// [Down] next palette row
+  {
+    draw_cursor (WINBG, false);
+    INCIDX (i, columns);
+    is_drawn &= ~(YID_TEXT | YID_CURSOR);
+    cursor_phase = 0;
+  }
+  else if (is.key == YK_END		// [End], [$]: end of current line
+      || is.key == '$')
+  {
+    draw_cursor (WINBG, false);
+    i += columns - i % columns - 1;
+    is_drawn &= ~(YID_TEXT | YID_CURSOR);
+    cursor_phase = 0;
+  }
+  else if (is.key == YK_HOME		// [Home], [0], [^]: start of cur. line
+      || is.key == '^'
+      || is.key == '0')
+  {
+    draw_cursor (WINBG, false);
+    i -= i % columns;
+    is_drawn &= ~(YID_TEXT | YID_CURSOR);
+    cursor_phase = 0;
+  }
+  else if (is.key == YK_RETURN)		// [Return]: beginning of next line
+  {
+    draw_cursor (WINBG, false);
+    i += columns - i % columns;
+    is_drawn &= ~(YID_TEXT | YID_CURSOR);
+    cursor_phase = 0;
+  }
+#if 0  /* Conflicts with "rotate" */
+  else if (is.key == '-')		// [-]: beginning of previous line
+  {
+    draw_cursor (WINBG, false);
+    i -= columns + i % columns;
+    is_drawn &= ~(YID_TEXT | YID_CURSOR);
+    cursor_phase = 0;
+  }
+#endif
+  else if (is.key == 'G' 		// [G], [L]: beginning of last line
+      || is.key == 'L')
+  {
+    draw_cursor (WINBG, false);
+    i = (lines  - 1) * columns;
+    is_drawn &= ~(YID_TEXT | YID_CURSOR);
+    cursor_phase = 0;
+  }
+  else if (is.key == 'H')		// [H] beginning of first line
+  {
+    draw_cursor (WINBG, false);
+    i = 0;
+    is_drawn &= ~(YID_TEXT | YID_CURSOR);
+    cursor_phase = 0;
+  }
+  else if (is.key == 'm')		// [m] toggle mapping
+  {
+    mapping = ! mapping;
+    is_drawn &= ~(YID_PALETTE | YID_TEXT);
+  }
+  else if (is.key == 'M')		// [M] beginning of middle line
+  {
+    draw_cursor (WINBG, false);
+    i = (lines / 2) * columns;
+    is_drawn &= ~(YID_TEXT | YID_CURSOR);
+    cursor_phase = 0;
+  }
+  else if (is.key == '+' || is.key == '=')  // [+] increment offset
+  {
+    INCIDX (ofs, 1);
+    INCIDX (i, 1);
+    is_drawn &= ~(YID_PALETTE | YID_TEXT);
+  }
+  else if (is.key == '-')		// [-] decrement offset
+  {
+    DECIDX (ofs, 1);
+    DECIDX (i, 1);
+    is_drawn &= ~(YID_PALETTE | YID_TEXT);
+  }
+  else if (is.key == YK_ESC)		// [Esc] quit
+  {
+    break;
+  }
+  else if (is.key == YE_EXPOSE)
+  {
+    is_drawn = 0;  // Redraw everything
+  }
+  else
+    ;
+}
+
+pop_colour ();				// Restore current colour
+delete[] playpal;
+for (int n = 0; n < nmaps; n++)
+    delete colormap[n];
+delete[] colormap;
+}
+
+
+void Palette_viewer::draw_cursor (int c, bool phase)
+{
+  const int a = (i + ncolours - ofs) % ncolours;
+  const int side = pixels + 2;
+  const int x0 = ix0 - 1 + (side - 1) * (a % columns);
+  const int y0 = iy0 - 1 + (side - 1) * (a / columns);
+  const int x1 = x0 + side - 1;
+  const int y1 = y0 + side - 1;
+  if (c == WINBG)
+  {
+    set_colour (c);
+    DrawScreenRect (x0, y0, side, side);
+  }
+  else
+  {
+    const int l1 = side / 2;
+    const int l2 = side - l1;
+    // FIXME this cursor looks ugly
+    set_colour (phase ? BLACK : WHITE);
+    DrawScreenLineLen (x0, y0,  l1,   0);
+    DrawScreenLineLen (x0, y0,   0,  l1);
+    DrawScreenLineLen (x1, y1,   0, -l1);
+    DrawScreenLineLen (x1, y1, -l1,   0);
+    set_colour (phase ? WHITE : BLACK);
+    DrawScreenLineLen (x1, y0, -l2,   0);
+    DrawScreenLineLen (x1, y0,   0,  l2);
+    DrawScreenLineLen (x0, y1,   0, -l2);
+    DrawScreenLineLen (x0, y1,  l2,   0);
+  }
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/palview.h	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,30 @@
+/*
+ *	palview.h
+ *	Palette (PLAYPAL & COLORMAP) viewer
+ *	AYM 1999-11-11
+ */
+
+
+#ifndef YH_PALVIEW
+#define YH_PALVIEW
+
+
+class Palette_viewer
+{
+  public :
+    void run ();
+
+  private :
+    void draw_cursor (int c, bool phase);
+
+    static const int ncolours = DOOM_COLOURS;
+    static const int pixels   = 16;
+    static const int columns  = 16;
+    int              i;
+    int              ofs;
+    int              ix0;
+    int              iy0;
+};
+
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/patchdir.cc	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,365 @@
+/*
+ *	patchdir.cc
+ *	Patch_dir class
+ *	AYM 1999-11-25
+ */
+
+
+/*
+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 "patchdir.h"
+#include "wadfile.h"
+#include "wads.h"
+
+
+/* This class has only one instance, global and shared by
+   everyone. I don't think there would ever be a need for
+   multiple instances. Unless you add the capability to edit
+   levels from several different iwads simultaneously. But then,
+   how do you decide which windows are affected by loading a
+   pwad ? -- AYM 1999-11-27 */
+Patch_dir patch_dir;
+
+
+/*
+ *	ctor
+ */
+Patch_dir::Patch_dir ()
+{
+  pnames = 0;
+  npnames = 0;
+}
+
+
+/*
+ *	dtor
+ */
+Patch_dir::~Patch_dir ()
+{
+  if (pnames != 0)
+    FreeMemory (pnames);
+  if (! patch_lumps.empty ())
+    patch_lumps.clear ();
+}
+
+
+/*
+ *	Patch_dir::refresh
+ */
+void Patch_dir::refresh (MDirPtr master_dir)
+{
+  /* refresh() can be called more than once on the same object.
+     And usually is ! */
+  if (pnames != 0)
+  {
+    FreeMemory (pnames);
+    pnames = 0;
+    npnames = 0;
+  }
+  if (! patch_lumps.empty ())
+    patch_lumps.clear ();
+
+  /* First load PNAMES so that we known in which order we should
+     put the patches in the array. */
+  {
+    bool success = false;
+    const char *lump_name = "PNAMES";
+    do
+    {
+      MDirPtr dir;
+      i32 npatches_head = -42;
+      i32 npatches_body = -42;
+
+      dir = FindMasterDir (master_dir, lump_name);
+      if (dir == 0)
+      {
+	warn ("No %s lump, won't be able to render textures\n", lump_name);
+	break;
+      }
+      i32 pnames_body_size = dir->dir.size - 4;
+      if (pnames_body_size < 0)
+      {
+	warn ("Bad %s (negative size %ld), won't be able to render textures\n",
+	    lump_name, (long) dir->dir.size);
+	break;
+      }
+      if (pnames_body_size % 8)
+      {
+	warn ("%s lump has weird size %ld, discarding last %d bytes\n",
+	    (long) dir->dir.size, (int) (pnames_body_size % 8));
+      }
+      npatches_body = pnames_body_size / 8;
+      const Wad_file *wf = dir->wadfile;
+      wf->seek (dir->dir.start);
+      if (wf->error ())
+      {
+	warn ("%s: seek error\n", lump_name);
+	break;
+      }
+      wf->read_i32 (&npatches_head);
+      if (wf->error ())
+      {
+	warn ("%s: error reading header\n", lump_name);
+	break;
+      }
+      if (npatches_head > 0 && npatches_head < npatches_body)
+	npnames = npatches_head;
+      else
+	npnames = npatches_body;
+      if (npatches_head != npatches_body)
+      {
+	warn("%s: header says %ld patches, lump size suggests %ld,"
+	    " going for %lu\n",
+	    lump_name, long (npatches_head), long (npatches_body),
+	    (unsigned long) npnames);
+      }
+      if (npnames > 32767)
+      {
+	warn ("%s: too big (%lu patches), keeping only first 32767\n",
+	    lump_name, (unsigned long) npnames);
+	npnames = 32767;
+      }
+      pnames = (char *) GetMemory (npnames * WAD_PIC_NAME);
+      wf->read_bytes (pnames, npnames * WAD_PIC_NAME);
+      if (wf->error ())
+      {
+	warn ("%s: error reading names\n", lump_name);
+	break;
+      }
+      success = true;
+    }
+    while (0);
+    if (! success)
+      warn ("%s: errors found, won't be able to render textures\n", lump_name);
+  }
+
+  /* Get list of patches in the master directory. Everything
+     that is between P_START/P_END or PP_START/PP_END and that
+     is not a label is supposed to be a patch. */
+  {
+    for (MDirPtr dir = master_dir;
+	dir && (dir = FindMasterDir (dir, "P_START", "PP_START"));)
+    {
+      MDirPtr start_label = dir;
+      const char *end_label = 0;
+      if (! y_strnicmp (dir->dir.name, "P_START", WAD_NAME))
+	end_label = "P_END";
+      else if (! y_strnicmp (dir->dir.name, "PP_START", WAD_NAME))
+	end_label = "PP_END";
+      else
+	fatal_error ("Bad start label \"%.*s\"", (int) WAD_NAME, dir->dir.name);
+      //printf ("[%-8.8s ", dir->dir.name);  // DEBUG
+      //fflush (stdout);
+      dir = dir->next;
+      for (;; dir = dir->next)
+      {
+	if (! dir)
+	{
+	  warn ("%.128s: no matching %s for %.*s\n",
+	      start_label->wadfile->pathname (),
+	      end_label,
+	      (int) WAD_NAME, start_label->dir.name);
+	  break;
+	}
+	if (! y_strnicmp (dir->dir.name, end_label, WAD_NAME))
+	{
+	  if (dir->dir.size != 0)
+	    warn ("%.128s: label %.*s has non-zero size %ld\n",
+		dir->wadfile->pathname (),
+		(int) WAD_NAME, dir->dir.name,
+		(long) dir->dir.size);
+	  dir = dir->next;
+	  //printf ("%-8.8s]\n", dir->dir.name);  // DEBUG
+	  break;
+	} 
+	if (dir->dir.start == 0 || dir->dir.size == 0)
+	{
+	  if (! (toupper (dir->dir.name[0]) == 'P'
+	      && (dir->dir.name[1] == '1'
+	       || dir->dir.name[1] == '2'
+	       || dir->dir.name[1] == '3')
+	      && dir->dir.name[2] == '_'
+	      && (! y_strnicmp (dir->dir.name + 3, "START", WAD_NAME - 3)
+		  || ! y_strnicmp (dir->dir.name + 3, "END", WAD_NAME - 3))))
+	    warn ("%.128s: unexpected label \"%.*s\" among patches.\n",
+		dir->wadfile->pathname (), (int) WAD_NAME, dir->dir.name);
+	  continue;
+	}
+	//printf ("%-9.8s ", dir->dir.name); fflush (stdout);  // DEBUG
+	wad_flat_name_t name;
+	memcpy (name, dir->dir.name, sizeof name);
+	patch_lumps[name]
+	  = Lump_loc (dir->wadfile, dir->dir.start, dir->dir.size);
+      }
+      if (dir)
+        dir = dir->next;
+    }
+    //putchar ('\n');  // DEBUG
+  }
+#ifdef DEBUG
+  for (Patch_lumps_map::const_iterator i = patch_lumps.begin ();
+      i != patch_lumps.end (); i++)
+  {
+    printf ("%-8.8s %p %08lX %ld\n",
+      i->first._name,
+      i->second.wad,
+      i->second.ofs,
+      i->second.len);
+  }
+#endif
+}
+
+
+/*
+ *	loc_by_name
+ *	Return the (wad, offset, length) location of the lump
+ *	that contains patch <name>.
+ */
+void Patch_dir::loc_by_name (const char *name, Lump_loc& loc)
+{
+  Patch_lumps_map::const_iterator i = patch_lumps.find (name);
+  if (i == patch_lumps.end ())
+  {
+    loc.wad = 0;
+    return;
+  }
+  loc = i->second;
+}
+
+
+/*
+ *	loc_by_num
+ *	Return the (wad, offset, length) location of the lump
+ *	that contains patch# <num>.
+ */
+void Patch_dir::loc_by_num (i16 num, Lump_loc& loc)
+{
+  wad_pic_name_t *nm = name_for_num (num);
+  if (nm == 0)
+  {
+    loc.wad = 0;
+    return;
+  }
+  loc_by_name ((const char *) nm, loc);
+}
+
+
+/*
+ *	name_for_num
+ *	Return a pointer on the name of the patch of number <num>
+ *	or 0 if no such patch.
+ */
+wad_pic_name_t *Patch_dir::name_for_num (i16 num)
+{
+  if (num < 0 || (size_t) num >= npnames)  // Cast to silence GCC warning
+    return 0;
+  return (wad_pic_name_t *) (pnames + WAD_PIC_NAME * num);
+}
+
+
+/*
+ *	list
+ *	Put a list of all existing patch lump, sorted by name
+ *	and without duplicates, in <pl>.
+ */
+void Patch_dir::list (Patch_list& pl)
+{
+  pl.set (patch_lumps);
+}
+
+
+/*-------------------------- Patch_list --------------------------*/
+
+
+Patch_list::Patch_list ()
+{
+  array = 0;
+  nelements = 0;
+}
+
+
+Patch_list::~Patch_list ()
+{
+  clear ();
+}
+
+
+void Patch_list::set (Patch_lumps_map& patch_lumps)
+{
+  clear ();
+  nelements = patch_lumps.size ();
+  array = new char *[nelements];
+
+  Patch_lumps_map::const_iterator i = patch_lumps.begin ();
+  for (size_t n = 0; n < nelements; n++)
+  {
+    array[n] = new char[WAD_PIC_NAME + 1];
+    *array[n] = '\0';
+    strncat (array[n], i++->first._name, WAD_PIC_NAME);
+  }
+}
+
+
+void Patch_list::clear ()
+{
+  if (array != 0)
+  {
+    for (size_t n = 0; n < nelements; n++)
+      delete[] array[n];
+    delete[] array;
+  }
+}
+
+
+const char **Patch_list::data ()
+{
+  return (const char **) array;
+}
+
+
+size_t Patch_list::size ()
+{
+  return nelements;
+}
+
+
+/*---------------------------- Pllik -----------------------------*/
+
+
+Pllik::Pllik (const char *name)
+{
+  memcpy (_name, name, sizeof _name);
+}
+
+
+/*-------------------------- Pllik_less --------------------------*/
+
+
+bool Pllik_less::operator () (const Pllik &p1, const Pllik &p2) const
+{
+  return y_strnicmp ((const char *) &p1, (const char *) &p2, WAD_PIC_NAME) < 0;
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/patchdir.h	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,129 @@
+/*
+ *	patchdir.h
+ *	Patch_dir class
+ *	AYM 1999-11-25
+ */
+
+
+/*
+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.
+*/
+
+
+#ifndef YH_PATCHDIR
+#define YH_PATCHDIR
+
+
+#include <map>
+
+
+/*
+ *	Patch_dir 
+ *	
+ *	The purpose of this class is to hide the details of how
+ *	patches are stored in the wads from Yadex. It provides
+ *	two basic services :
+ *
+ *	- refresh()	Must be called every time the directory
+ *			changes in any way.
+ *
+ *	- loc_by_name()	Return the lump location (WadPtr,
+ *			offset, length) of a patch by name. Used
+ *			by the patch browser. If the patch does
+ *			not exist, returns a NULL WadPtr.
+ *
+ *	- loc_by_num()	Return the lump location (WadPtr,
+ *			offset, length) of a patch by number (as
+ *			in TEXTURE[12]). Used by the texture
+ *			browser. If the patch does not exist,
+ *			returns a NULL WadPtr.
+ *
+ *	- list()	Return a Patch_list object that provides
+ *			what InputNameFromListWithFunc() needs
+ *			to browse the patches. I suggest that
+ *			this object be created immediately
+ *			before it's needed and destroyed
+ *			immediately after because it is not
+ *			intended to remain valid across calls to
+ *			refresh(). Ignoring this advice will
+ *			cause some interesting crashes.
+ *
+ *	The lifetime of this class is about the same as the
+ *	lifetime of Yadex itself. It is instantiated only once.
+ *	After construction, it is "empty". You must call
+ *	refresh() to really initialize it (and call it again
+ *	every time the directory changes in any way or you'll
+ *	get strange results--or worse).
+ */
+
+struct Pllik
+{
+  Pllik (const char *name);
+  wad_pic_name_t _name;
+};
+
+struct Pllik_less
+{
+  bool operator() (const Pllik& p1, const Pllik& p2) const;
+};
+
+typedef std::map<Pllik, Lump_loc, Pllik_less> Patch_lumps_map;
+
+class Patch_list
+{
+  public :
+    Patch_list ();
+    ~Patch_list ();
+    const char **data ();
+    size_t size ();
+    void set (Patch_lumps_map& patch_lumps);
+    void clear ();
+
+  private :
+    char **array;
+    size_t nelements;
+};
+
+class Patch_dir
+{
+  public :
+    Patch_dir ();
+    ~Patch_dir ();
+    void refresh (MDirPtr master_dir);
+    void loc_by_name (const char *name, Lump_loc& loc);
+    void loc_by_num (i16 num, Lump_loc& loc);
+    wad_pic_name_t *name_for_num (i16 num);
+    void list (Patch_list& pl);
+
+  private :
+    char *pnames;			// The contents of PNAMES
+    					// (block of npnames x 8 chars)
+    size_t npnames;			// Number of entries in PNAMES
+    Patch_lumps_map patch_lumps;	// List of patch lumps, sorted
+    					// by name (no duplicates), with
+					// their location.
+};
+
+
+extern Patch_dir patch_dir;		// Only one instance and it's global
+
+
+#endif  /* DO NOT ADD ANYTHING AFTER THIS LINE */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/pic2img.cc	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,486 @@
+/*
+ *	pic2img.cc
+ *	Loading Doom-format pictures from a wad file.
+ *	See the Unofficial Doom Specs, section [5-1].
+ *	AYM 1998-??-??
+ */
+
+
+/*
+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 "gcolour2.h"  /* colour0 */
+#include "pic2img.h"
+#include "wadfile.h"
+#include "wads.h"
+
+
+typedef enum { _MT_BADOFS, _MT_TOOLONG, _MT_TOOMANY } _msg_type_t;
+
+
+static int add_msg (char type, int arg);
+static void do_add_msg (char type, int arg);
+static void flush_msg (const char *picname);
+
+
+/*
+ *	LoadPicture - read a picture from a wad file into an Img object
+ *
+ *	If img->is_null() is false, LoadPicture() does not allocate the
+ *	buffer itself. The buffer and the picture don't have to have the
+ *	same dimensions. Thanks to this, it can also be used to compose
+ *	textures : you allocate a single buffer for the whole texture
+ *	and then you call LoadPicture() on it once for each patch.
+ *	LoadPicture() takes care of all the necessary clipping.
+ *
+ *	If img->is_null() is true, LoadPicture() sets the size of img
+ *	to match that of the picture. This is useful in display_pic().
+ *
+ *	Return 0 on success, non-zero on failure.
+ *
+ *	If pic_x_offset == INT_MIN, the picture is centred horizontally.
+ *	If pic_y_offset == INT_MIN, the picture is centred vertically.
+ */
+
+int LoadPicture (
+   Img& img,			// Game image to load picture into
+   const char *picname,		// Picture lump name
+   const Lump_loc& picloc,	// Picture lump location
+   int pic_x_offset,		// Coordinates of top left corner of picture
+   int pic_y_offset, 		// relative to top left corner of buffer
+   int *pic_width,		// To return the size of the picture
+   int *pic_height)		// (can be NULL)
+{
+MDirPtr	dir;
+i16	pic_width_;
+i16	pic_height_;
+i16	pic_intrinsic_x_ofs;
+i16	pic_intrinsic_y_ofs;
+u8	*ColumnData;
+u8	*Column;
+i32	*NeededOffsets;
+i32	CurrentOffset;
+int	ColumnInMemory;
+long	ActualBufLen;
+int	pic_x;
+int	pic_x0;
+int	pic_x1;
+int	pic_y0;
+int	pic_y1;
+u8      *buf;	/* This variable is set to point to the element of
+		   the image buffer where the top of the current column
+		   should be pasted. It can be off the image buffer! */
+
+// Locate the lump where the picture is
+if (picloc.wad != 0)
+   {
+   MasterDirectory dirbuf;
+   dirbuf.wadfile   = picloc.wad;
+   dirbuf.dir.start = picloc.ofs;
+   dirbuf.dir.size  = picloc.len;
+   dir = &dirbuf;
+   }
+else
+   {
+   dir = (MDirPtr) FindMasterDir (MasterDir, picname);
+   if (dir == NULL)
+      {
+      warn ("picture %.*s does not exist.\n", WAD_PIC_NAME, picname);
+      return 1;
+      }
+   }
+
+// Read the picture header
+dir->wadfile->seek (dir->dir.start);
+if (dir->wadfile->error ())
+   {
+   warn ("picture %.*s: can't seek to header, giving up\n",
+         WAD_PIC_NAME, picname);
+   return 1;
+   }
+bool dummy_bytes  = dir->wadfile->pic_format () == YGPF_NORMAL;
+bool long_header  = dir->wadfile->pic_format () != YGPF_ALPHA;
+bool long_offsets = dir->wadfile->pic_format () == YGPF_NORMAL;
+if (long_header)
+   {
+   dir->wadfile->read_i16 (&pic_width_);
+   dir->wadfile->read_i16 (&pic_height_);
+   dir->wadfile->read_i16 (&pic_intrinsic_x_ofs);  // Read but ignored
+   dir->wadfile->read_i16 (&pic_intrinsic_y_ofs);  // Read but ignored
+   if (dir->wadfile->error ())
+      {
+      warn ("picture %.*s: read error in header, giving up\n",
+	    WAD_PIC_NAME, picname);
+      return 1;
+      }
+   }
+else
+   {
+   pic_width_          = dir->wadfile->read_u8 ();
+   pic_height_         = dir->wadfile->read_u8 ();
+   pic_intrinsic_x_ofs = dir->wadfile->read_u8 ();  // Read but ignored
+   pic_intrinsic_y_ofs = dir->wadfile->read_u8 ();  // Read but ignored
+   if (dir->wadfile->error ())
+      {
+      warn ("picture %.*s: read error in header, giving up\n",
+	    WAD_PIC_NAME, picname);
+      return 1;
+      }
+   }
+
+// If no buffer given by caller, allocate one.
+if (img.is_null ())
+   {
+   // Sanity checks
+   if (pic_width_  < 1 || pic_height_ < 1)
+      {
+      warn ("picture %.*s: delirious dimensions %dx%d, giving up\n",
+	    WAD_PIC_NAME, picname, (int) pic_width_, (int) pic_height_);
+      }
+   const int pic_width_max = 4096;
+   if (pic_width_ > pic_width_max)
+      {
+      warn ("picture %.*s: too wide (%d), clipping to %d\n",
+	    WAD_PIC_NAME, picname, (int) pic_width_, pic_width_max);
+      pic_width_ = pic_width_max;
+      }
+   const int pic_height_max = 4096;
+   if (pic_height_ > pic_height_max)
+      {
+      warn ("picture %.*s: too high (%d), clipping to %d\n",
+	    WAD_PIC_NAME, picname, (int) pic_height_, pic_height_max);
+      pic_height_ = pic_height_max;
+      }
+   img.resize (pic_width_, pic_height_);
+   }
+int img_width = img.width ();
+
+// Centre the picture.
+if (pic_x_offset == INT_MIN)
+   pic_x_offset = (img_width - pic_width_) / 2;
+if (pic_y_offset == INT_MIN)
+   pic_y_offset = (img.height () - pic_height_) / 2;
+
+/* AYM 19971202: 17 kB is large enough for 128x128 patches. */
+#define TEX_COLUMNBUFFERSIZE ((long) 17 * 1024)
+/* Maximum number of bytes per column. The worst case is a
+   509-high column, with every second pixel transparent. That
+   makes 255 posts of 1 pixel, and a final FFh. The total is
+   (255 x 5 + 1) = 1276 bytes per column. */
+#define TEX_COLUMNSIZE  1300
+
+ColumnData    = (u8 *) GetMemory (TEX_COLUMNBUFFERSIZE);
+/* FIXME DOS and pic_width_ > 16000 */
+NeededOffsets = (i32 *) GetMemory ((long) pic_width_ * 4);
+
+if (long_offsets)
+   dir->wadfile->read_i32 (NeededOffsets, pic_width_);
+else
+   for (int n = 0; n < pic_width_; n++)
+      {
+      i16 ofs;
+      dir->wadfile->read_i16 (&ofs);
+      NeededOffsets[n] = ofs;
+      }
+if (dir->wadfile->error ())
+   {
+   warn ("picture %.*s: read error in offset table, giving up\n",
+	 WAD_PIC_NAME, picname);
+   FreeMemory (ColumnData);
+   FreeMemory (NeededOffsets);
+   return 1;
+   }
+
+// Read first column data, and subsequent column data
+if (long_offsets && NeededOffsets[0] != 8 + (long) pic_width_ * 4
+|| !long_offsets && NeededOffsets[0] != 4 + (long) pic_width_ * 2)
+   {
+   dir->wadfile->seek (dir->dir.start + NeededOffsets[0]);
+   if (dir->wadfile->error ())
+      {
+      warn ("picture %.*s: can't seek to header, giving up\n",
+         WAD_PIC_NAME, picname);
+      FreeMemory (ColumnData);
+      FreeMemory (NeededOffsets);
+      return 1;
+      }
+   }
+ActualBufLen = dir->wadfile->read_vbytes (ColumnData, TEX_COLUMNBUFFERSIZE);
+// FIXME should catch I/O errors
+
+// Clip the picture horizontally and vertically
+pic_x0 = - pic_x_offset;
+if (pic_x0 < 0)
+  pic_x0 = 0;
+
+pic_x1 = img_width - pic_x_offset - 1;
+if (pic_x1 >= pic_width_)
+  pic_x1 = pic_width_ - 1;
+
+pic_y0 = - pic_y_offset;
+if (pic_y0 < 0)
+  pic_y0 = 0;
+
+pic_y1 = img.height () - pic_y_offset - 1;
+if (pic_y1 >= pic_height_)
+  pic_y1 = pic_height_ - 1;
+
+// For each (non clipped) column of the picture...
+for (pic_x = pic_x0,
+   buf = img.wbuf () + al_amax (pic_x_offset, 0) + img_width * pic_y_offset;
+   pic_x <= pic_x1;
+   pic_x++, buf++)
+   {
+   u8 *filedata;
+
+   CurrentOffset  = NeededOffsets[pic_x];
+   ColumnInMemory = CurrentOffset >= NeededOffsets[0]
+      && CurrentOffset + TEX_COLUMNSIZE <= NeededOffsets[0] + ActualBufLen;
+   if (ColumnInMemory)
+      Column = ColumnData + CurrentOffset - NeededOffsets[0];
+   else
+      {
+      Column = (u8 *) GetFarMemory (TEX_COLUMNSIZE);
+      dir->wadfile->seek (dir->dir.start + CurrentOffset);
+      if (dir->wadfile->error ())
+         {
+	 int too_many = add_msg (_MT_BADOFS, (short) pic_x);
+	 FreeFarMemory (Column);
+	 if (too_many)		// This picture has too many errors. Give up.
+	    goto pic_end;
+	 continue;			// Give up on this column
+         }
+      dir->wadfile->read_vbytes (Column, TEX_COLUMNSIZE);
+      // FIXME should catch I/O errors
+      }
+   filedata = Column;
+
+   // We now have the needed column data, one way or another, so write it
+ 
+   // For each post of the column...
+   {
+   register u8 *post;
+   for (post = filedata; *post != 0xff;)
+      {
+      int post_y_offset;	// Y-offset of top of post to origin of buffer
+      int post_height;		// Height of post
+      int post_pic_y0;		// Start and end of non-clipped part of post,
+      int post_pic_y1;		// relative to top of picture
+      int post_y0;		// Start and end of non-clipped part of post,
+      int post_y1;		// relative to top of post
+
+      if (post - filedata > TEX_COLUMNSIZE)
+         {
+	 int too_many = add_msg (_MT_TOOLONG, (short) pic_x);
+	 if (too_many)		// This picture has too many errors. Give up.
+	    {
+	    if (! ColumnInMemory)
+	       FreeFarMemory (Column);
+	    goto pic_end;
+	    }
+	 break;				// Give up on this column
+	 }
+
+      post_y_offset = *post++;
+      post_height = *post++;
+      if (dummy_bytes)
+         post++;			// Skip that dummy byte
+
+      post_pic_y0 = post_y_offset;	// Clip the post vertically
+      if (post_pic_y0 < pic_y0)
+	 post_pic_y0 = pic_y0;
+      
+      post_pic_y1 = post_y_offset + post_height - 1;
+      if (post_pic_y1 > pic_y1)
+	 post_pic_y1 = pic_y1;
+
+      post_y0 = post_pic_y0 - post_y_offset;
+      post_y1 = post_pic_y1 - post_y_offset;
+
+
+      {					// "Paste" the post onto the buffer
+      register img_pixel_t *b;
+      register const u8 *p          = post + post_y0;
+               const u8 *const pmax = post + post_y1;
+      int buf_width = img_width;
+
+      for (b = buf + buf_width * (post_y_offset + post_y0);
+	 p <= pmax;
+	 b += buf_width, p++)
+         {
+#ifdef PARANOIA
+         if (b < img.buf ())
+	    {
+            nf_bug ("Picture %.*s(%d): b < buffer",
+		WAD_PIC_NAME, picname, (int) pic_x);
+	    goto next_column;
+	    }
+#endif
+	 *b = (*p == IMG_TRANSP) ? colour0 : *p;
+         }
+      }
+
+      post += post_height;
+      if (dummy_bytes)
+         post++;			// Skip the trailing dummy byte
+      }  // Post loop
+   }
+
+#ifdef PARANOIA
+next_column :
+#endif
+   if (!ColumnInMemory)
+      FreeFarMemory (Column);
+   }  // Column loop
+
+pic_end:
+FreeMemory (ColumnData);
+FreeMemory (NeededOffsets);
+flush_msg (picname);
+#if 0
+c->flags |= HOOK_DRAWN;
+#endif
+if (pic_width)
+   *pic_width  = pic_width_;
+if (pic_height)
+   *pic_height = pic_height_;
+return 0;
+}
+
+
+/*
+ *	List to hold pending warning messages
+ */
+typedef struct
+{
+   char type;
+   short arg;
+} _msg_t;
+static _msg_t *_msg_list  = 0;
+static size_t _nmsg       = 0;
+const size_t _granularity = 128;
+const size_t _max_msg     = 20;
+
+
+/*
+ *	add_msg
+ *	Add a warning message to the list
+ *
+ *	Return 0 on success, <>0 if the max number of messages
+ *	has been reached.
+ */
+static int add_msg (char type, int arg)
+{
+if (_nmsg >= _max_msg)
+   {
+   if (_nmsg == _max_msg)  // Test in case the caller ignores our return value
+      do_add_msg (_MT_TOOMANY, arg);
+   return 1;
+   }
+do_add_msg (type, arg);
+return 0;
+}
+
+
+static void do_add_msg (char type, int arg)
+{
+if ((_nmsg + 1) % _granularity == 1)  // Grow list if necessary
+   {
+   _msg_t *new_list = (_msg_t *) realloc (_msg_list,
+	 (_nmsg / _granularity + 1) * _granularity * sizeof *_msg_list);
+   if (new_list == 0)  // Not enough memory ? Ignore the new message
+      return;
+   _msg_list = new_list;
+   }
+_msg_list[_nmsg].type = type;
+_msg_list[_nmsg].arg  = arg;
+_nmsg++;
+return;
+}
+
+
+/*
+ *	flush_msg
+ *	Output all pending warning messages in an smart fashion
+ */
+static void flush_msg (const char *picname)
+{
+if (_nmsg == 0 || _msg_list == 0)
+   return;
+
+for (_msg_type_t t = _MT_BADOFS; t <= _MT_TOOLONG; ((int &) t)++)
+   {
+   size_t first_msg = AL_ASIZE_T_MAX;
+   size_t last_msg = AL_ASIZE_T_MAX;
+   const char *str = "unknown error";
+   if (t == _MT_BADOFS)
+      str = "bad file offset";
+   else if (t == _MT_TOOLONG)
+      str = "post too long";
+
+   for (size_t n = 0; n < _nmsg; n++)
+      {
+      if (_msg_list[n].type == t)
+	 {
+	 if (first_msg == AL_ASIZE_T_MAX)
+	    {
+	    first_msg = n;
+	    last_msg = n;
+	    }
+	 else
+	    {
+	    if (_msg_list[last_msg].arg != _msg_list[n].arg - 1)
+	       {
+	       warn ("picture %.*s(%d",
+		  WAD_PIC_NAME, picname, (int) _msg_list[first_msg].arg);
+	       if (last_msg != first_msg)
+		  warn ("-%d", (int) _msg_list[last_msg].arg);
+	       warn ("): %s. Corrupt wad ?\n", str);
+	       first_msg = n;
+	       last_msg = n;
+	       }
+	    else
+	       last_msg = n;
+	    }
+	 }
+      }
+   if (first_msg != AL_ASIZE_T_MAX)
+      {
+      warn ("picture %.*s(%d",
+	    WAD_PIC_NAME, picname, (int) _msg_list[first_msg].arg);
+      if (last_msg != first_msg)
+	 warn ("-%d", (int) _msg_list[last_msg].arg);
+      warn ("): %s. Corrupt wad ?\n", str);
+      }
+   }
+
+if (_msg_list[_nmsg - 1].type == _MT_TOOMANY)
+   warn ("picture %.*s: too many errors. Giving up.\n", WAD_PIC_NAME, picname);
+_nmsg = 0;
+free (_msg_list);
+_msg_list = 0;
+}
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/pic2img.h	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,36 @@
+/*
+ *	pic2img.h
+ *	AYM 1998-??-??
+ */
+
+
+#ifndef YH_PIC2IMG  /* DO NOT INSERT ANYTHING BEFORE THIS LINE */
+#define YH_PIC2IMG
+
+
+#include "img.h"
+
+
+/* LoadPicture() normally attempts to load the whole picture lump
+   into memory at once. However, this variable sets an upper limit
+   to the size of the buffer that it allocates. If the picture is
+   larger than this, it will be read in several passes. */
+#define MAX_PICTURE_BUFFER_SIZE 100000
+
+
+int LoadPicture (
+   Img& img,
+#if 0
+   img_pixel_t *buffer,	/* Buffer to load picture into */
+   int buf_width,		/* Dimensions of the buffer */
+   int buf_height,
+#endif
+   const char *picname,		/* Picture lump name */
+   const Lump_loc& picloc,	/* Picture lump name */
+   int pic_x_offset,		/* Coordinates of top left corner of picture */
+   int pic_y_offset,		/* relative to top left corner of buffer. */
+   int *pic_width = 0,		/* To return the size of the picture */
+   int *pic_height = 0);	/* (can be NULL) */
+
+
+#endif  /* DO NOT ADD ANYTHING AFTER THIS LINE */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/prefer.cc	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,163 @@
+/*
+ *	prefer.cc
+ *	AYM 1998-10-17
+ */
+
+
+/*
+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 "entry.h"
+#include "flats.h"
+#include "gfx.h"
+#include "levels.h"
+#include "oldmenus.h"
+#include "prefer.h"
+#include "textures.h"
+
+
+/*
+   display a "Preferences" menu (change default textures, etc.)
+*/
+
+void Preferences (int x0, int y0)
+{
+char   *menustr[9];
+int     n, val;
+char    texname[WAD_TEX_NAME + 1];
+char    flatname[WAD_FLAT_NAME + 1];
+int     width;
+int     height;
+
+width  = 2 * BOX_BORDER + 2 * WIDE_HSPACING + 50 * FONTW;
+height = 2 * BOX_BORDER + 2 * WIDE_VSPACING + (int) (10.5 * FONTH);
+if (x0 < 0)
+   x0 = (ScrMaxX + 1 - width) / 2;
+if (y0 < 0)
+   y0 = (ScrMaxY + 1 - height) / 2;
+for (n = 0; n < 9; n++)
+   menustr[n] = (char *) GetMemory (80);
+sprintf (menustr[8], "Preferences");
+sprintf (menustr[0], "Change default middle texture  (Current: %.*s)",
+   (int) WAD_TEX_NAME, default_middle_texture);
+sprintf (menustr[1], "Change default upper texture   (Current: %.*s)",
+   (int) WAD_TEX_NAME, default_upper_texture);
+sprintf (menustr[2], "Change default lower texture   (Current: %.*s)",
+   (int) WAD_TEX_NAME, default_lower_texture);
+sprintf (menustr[3], "Change default floor texture   (Current: %.*s)",
+   (int) WAD_FLAT_NAME, default_floor_texture);
+sprintf (menustr[4], "Change default ceiling texture (Current: %.*s)",
+   (int) WAD_FLAT_NAME, default_ceiling_texture);
+sprintf (menustr[5], "Change default floor height    (Current: %d)",
+   default_floor_height);
+sprintf (menustr[6], "Change default ceiling height  (Current: %d)",
+   default_ceiling_height);
+sprintf (menustr[7], "Change default light level     (Current: %d)",
+   default_light_level);
+val = vDisplayMenu (x0, y0, menustr[8],
+  menustr[0], YK_, 0,
+  menustr[1], YK_, 0,
+  menustr[2], YK_, 0,
+  menustr[3], YK_, 0,
+  menustr[4], YK_, 0,
+  menustr[5], YK_, 0,
+  menustr[6], YK_, 0,
+  menustr[7], YK_, 0,
+  NULL);
+for (n = 0; n < 9; n++)
+   FreeMemory (menustr[n]);
+int subwin_x0 = x0 + BOX_BORDER + WIDE_HSPACING;
+int subwin_y0 = y0 + BOX_BORDER + WIDE_VSPACING + (int) ((1.5 + val) * FONTH);
+switch (val)
+   {
+   case 1:
+      strcpy (texname, default_middle_texture);
+      ChooseWallTexture (subwin_x0, subwin_y0, "Choose a wall texture",
+        NumWTexture, WTexture, texname);
+      if (strlen (texname) > 0)
+	 strcpy (default_middle_texture, texname);
+      break;
+   case 2:
+      strcpy (texname, default_upper_texture);
+      ChooseWallTexture (subwin_x0, subwin_y0, "Choose a wall texture",
+        NumWTexture, WTexture, texname);
+      if (strlen (texname) > 0)
+	 strcpy (default_upper_texture, texname);
+      break;
+   case 3:
+      strcpy (texname, default_lower_texture);
+      ChooseWallTexture (subwin_x0, subwin_y0, "Choose a wall texture",
+        NumWTexture, WTexture, texname);
+      if (strlen (texname) > 0)
+	 strcpy (default_lower_texture, texname);
+      break;
+   case 4:
+      {
+      strcpy (flatname, default_floor_texture);
+      char ** flat_names
+	= (char **) GetMemory (NumFTexture * sizeof *flat_names);
+      for (size_t n = 0; n < NumFTexture; n++)
+	 flat_names[n] = flat_list[n].name;
+      ChooseFloorTexture (subwin_x0, subwin_y0, "Choose a floor texture",
+        NumFTexture, flat_names, flatname);
+      FreeMemory (flat_names);
+      if (strlen (flatname) > 0)
+	 strcpy (default_floor_texture, flatname);
+      break;
+      }
+   case 5:
+      {
+      strcpy (flatname, default_ceiling_texture);
+      char ** flat_names
+	= (char **) GetMemory (NumFTexture * sizeof *flat_names);
+      for (size_t n = 0; n < NumFTexture; n++)
+	 flat_names[n] = flat_list[n].name;
+      ChooseFloorTexture (subwin_x0, subwin_y0, "Choose a ceiling texture",
+        NumFTexture, flat_names, flatname);
+      FreeMemory (flat_names);
+      if (strlen (flatname) > 0)
+	 strcpy (default_ceiling_texture, flatname);
+      break;
+      }
+   case 6:
+      val = InputIntegerValue (x0 + 42, subwin_y0, -512, 511, default_floor_height);
+      if (val != IIV_CANCEL)
+	 default_floor_height = val;
+      break;
+   case 7:
+      val = InputIntegerValue (x0 + 42, subwin_y0, -512, 511, default_ceiling_height);
+      if (val != IIV_CANCEL)
+	 default_ceiling_height = val;
+      break;
+   case 8:
+      val = InputIntegerValue (x0 + 42, subwin_y0, 0, 255, default_light_level);
+      if (val != IIV_CANCEL)
+	 default_light_level = val;
+      break;
+     
+   }
+}
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/prefer.h	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,9 @@
+/*
+ *	prefer.h
+ *	AYM 1998-10-17
+ */
+
+
+void Preferences (int x0, int y0);
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/record.h	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,23 @@
+/*
+ *	record.h - record events for later playback
+ *	AYM 2000-05-17
+ */
+
+
+#ifndef YH_RECORD  /* DO NOT INSERT ANYTHING BEFORE THIS LINE */
+#define YH_RECORD
+
+
+class Recording 
+{
+  public :
+    read ();
+    write ();
+
+  private :
+    class priv;
+    priv *p;
+};
+
+
+#endif  /* DO NOT ADD ANYTHING AFTER THIS LINE */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/rgb.h	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,70 @@
+/*
+ *	rgb.h
+ *	AYM 1998-11-28
+ */
+
+
+/*
+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.
+*/
+
+
+#ifndef YH_RGB  /* Prevent multiple inclusion */
+#define YH_RGB  /* Prevent multiple inclusion */
+
+
+class rgb_c
+   {
+   public :
+      rgb_c ()
+         {
+         }
+
+      // Must be defined before rbg_c (r, g, b)
+      void set (u8 red, u8 green, u8 blue)
+         {
+         r = red;
+         g = green;
+         b = blue;
+         }
+
+      rgb_c (u8 red, u8 green, u8 blue)
+         {
+         set (red, green, blue);
+         }
+
+      int operator == (const rgb_c& rgb2) const
+         {
+         return rgb2.r == r && rgb2.g == g && rgb2.b == b;
+         }
+
+      int operator - (const rgb_c& rgb2) const
+         {
+         return abs (rgb2.r - r) + abs (rgb2.g - g) + abs (rgb2.b - b);
+         }
+
+      u8 r;
+      u8 g;
+      u8 b;
+   };
+
+
+#endif  /* DO NOT ADD ANYTHING AFTER THIS LINE */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/rgbbmp.h	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,151 @@
+/*
+ *	rgbbmp.h
+ *	Rgbbmp - An RGB bitmap image class.
+ *
+ *	This is a simple bitmap where each pixel is an RGB
+ *	triplet. Each component is coded as an 8-bit unsigned
+ *	integer (of type u8).
+ *
+ *	AYM 1999-06-06
+ */
+
+
+/*
+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.
+*/
+ 
+ 
+#ifndef YH_RGBBMP
+#define YH_RGBBMP
+
+
+typedef struct
+{
+  u8 r;
+  u8 g;
+  u8 b;
+} Rgbbmp_pixel_t;
+
+
+class Rgbbmp
+{
+  public :
+
+    Rgbbmp ()
+    {
+      _width = 0;
+      _height = 0;
+      pixel = 0;
+    }
+
+    void resize (int width, int height)  // Must be defined before first use
+    {
+      _width  = width;
+      _height = height;
+      if (pixel)
+	delete[] pixel;
+      if (width * height > 0)
+        pixel = new Rgbbmp_pixel_t[width * height];
+      else
+	pixel = 0;
+    };
+
+    Rgbbmp (int width, int height)
+    {
+      pixel = 0;
+      resize (width, height);
+    }
+
+    ~Rgbbmp ()
+    {
+      if (pixel)
+	delete[] pixel;
+    }
+
+    int width () const
+    {
+      return _width;
+    }
+
+    int height () const
+    {
+      return _height;
+    }
+
+    void clear ()
+    {
+      if (pixel)
+	memset (pixel, 0, _width * _height * sizeof *pixel);
+    }
+
+    void get (int x, int y, u8 &r, u8 &g, u8 &b) const
+    {
+      r = pixel[y * _width + x].r;
+      g = pixel[y * _width + x].g;
+      b = pixel[y * _width + x].b;
+    }
+
+    u8 get_r (int x, int y) const
+    {
+      return pixel[y * _width + x].r;
+    }
+
+    u8 get_g (int x, int y) const
+    {
+      return pixel[y * _width + x].g;
+    }
+
+    u8 get_b (int x, int y) const
+    {
+      return pixel[y * _width + x].b;
+    }
+
+    void set (int x, int y, u8 r, u8 g, u8 b)
+    {
+      pixel[y * _width + x].r = r;
+      pixel[y * _width + x].g = g;
+      pixel[y * _width + x].b = b;
+    }
+
+    void set_r (int x, int y, u8 r)
+    {
+      pixel[y * _width + x].r = r;
+    }
+
+    void set_g (int x, int y, u8 g)
+    {
+      pixel[y * _width + x].g = g;
+    }
+
+    void set_b (int x, int y, u8 b)
+    {
+      pixel[y * _width + x].b = b;
+    }
+
+  private :
+
+    int _width;
+    int _height;
+    Rgbbmp_pixel_t *pixel;
+};
+
+
+#endif  /* DO NOT ADD ANYTHING AFTER THIS LINE */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/s_centre.cc	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,109 @@
+/*
+ *	s_centre.cc
+ *	AYM 1998-11-22
+ */
+
+
+/*
+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 "bitvec.h"
+#include "levels.h"
+#include "s_centre.h"
+#include "s_vertices.h"
+
+
+/*
+ *	centre_of_sector
+ *	Return the coordinates of the centre of a sector.
+ *
+ *	FIXME The algorithm is desesperatingly simple-minded and
+ *	does not take into account concave sectors and sectors
+ *	that are enclosed by several distinct paths of linedefs.
+ */
+void centre_of_sector (obj_no_t s, int *x, int *y)
+{
+bitvec_c *vertices = bv_vertices_of_sector (s);
+long x_sum  = 0;
+long y_sum  = 0;
+int  nitems = 0;
+
+for (size_t n = 0; n < vertices->nelements (); n++)
+   if (vertices->get (n))
+      {
+      x_sum += Vertices[n].x;
+      y_sum += Vertices[n].y;
+      nitems++;
+      }
+if (nitems == 0)
+   {
+   *x = 0;
+   *y = 0;
+   }
+else
+   {
+   *x = (int) (x_sum / nitems);
+   *y = (int) (y_sum / nitems);
+   }
+delete vertices;
+}
+
+
+/*
+ *	centre_of_sectors
+ *	Return the coordinates of the centre of a group of sectors.
+ */
+void centre_of_sectors (SelPtr list, int *x, int *y)
+{
+bitvec_c *vertices;
+int nitems;
+long x_sum;
+long y_sum;
+int n;
+
+vertices = bv_vertices_of_sectors (list);
+x_sum = 0;
+y_sum = 0;
+nitems = 0;
+for (n = 0; n < NumVertices; n++)
+   if (vertices->get (n))
+      {
+      x_sum += Vertices[n].x;
+      y_sum += Vertices[n].y;
+      nitems++;
+      }
+if (nitems == 0)
+   {
+   *x = 0;
+   *y = 0;
+   }
+else
+   {
+   *x = (int) (x_sum / nitems);
+   *y = (int) (y_sum / nitems);
+   }
+delete vertices;
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/s_centre.h	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,13 @@
+/*
+ *	s_centre.h
+ *	AYM 1998-11-22
+ */
+
+
+#include "objid.h"
+
+
+void centre_of_sector (obj_no_t s, int *x, int *y);
+void centre_of_sectors (SelPtr list, int *x, int *y);
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/s_door.cc	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,150 @@
+/*
+ *	s_door.cc
+ *	Make door from sector
+ *	AYM 1998-02-03
+ */
+
+
+/*
+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 "dialog.h"
+#include "levels.h"
+#include "objid.h"
+#include "selectn.h"
+
+
+/*
+   turn a sector into a door: change the linedefs and sidedefs
+*/
+
+void MakeDoorFromSector (int sector) /* SWAP! */
+{
+int    sd1, sd2;
+int    n, s;
+SelPtr ldok, ldflip, ld1s;
+
+ldok = NULL;
+ldflip = NULL;
+ld1s = NULL;
+s = 0;
+/* build lists of linedefs that border the sector */
+for (n = 0; n < NumLineDefs; n++)
+{
+   ObjectsNeeded (OBJ_LINEDEFS, 0);
+   sd1 = LineDefs[n].sidedef1;
+   sd2 = LineDefs[n].sidedef2;
+   if (sd1 >= 0 && sd2 >= 0)
+   {
+      ObjectsNeeded (OBJ_SIDEDEFS, 0);
+      if (SideDefs[sd2].sector == sector)
+      {
+	 SelectObject (&ldok, n); /* already ok */
+	 s++;
+      }
+      if (SideDefs[sd1].sector == sector)
+      {
+	 SelectObject (&ldflip, n); /* must be flipped */
+	 s++;
+      }
+   }
+   else if (sd1 >= 0 && sd2 < 0)
+   {
+      ObjectsNeeded (OBJ_SIDEDEFS, 0);
+      if (SideDefs[sd1].sector == sector)
+	 SelectObject (&ld1s, n); /* wall (one-sided) */
+   }
+}
+/* a normal door has two sides... */
+if (s < 2)
+{
+   Beep ();
+   Notify (-1, -1, "The door must be connected to two other Sectors.", NULL);
+   ForgetSelection (&ldok);
+   ForgetSelection (&ldflip);
+   ForgetSelection (&ld1s);
+   return;
+}
+if ((s > 2) && !(Expert || Confirm (-1, -1, "The door will have more than two sides.", "Do you still want to create it?")))
+{
+   ForgetSelection (&ldok);
+   ForgetSelection (&ldflip);
+   ForgetSelection (&ld1s);
+   return;
+}
+/* flip the linedefs that have the wrong orientation */
+if (ldflip != NULL)
+   FlipLineDefs (ldflip, 1);
+/* merge the two selection lists */
+while (ldflip != NULL)
+{
+   if (!IsSelected (ldok, ldflip->objnum))
+      SelectObject (&ldok, ldflip->objnum);
+   UnSelectObject (&ldflip, ldflip->objnum);
+}
+/* change the linedefs and sidedefs */
+while (ldok != NULL)
+{
+   /* give the "normal door" type and flags to the linedef */
+   ObjectsNeeded (OBJ_LINEDEFS, 0);
+   n = ldok->objnum;
+   LineDefs[n].type = 1;
+   LineDefs[n].flags = 0x04;
+   sd1 = LineDefs[n].sidedef1; /* outside */
+   sd2 = LineDefs[n].sidedef2; /* inside */
+   /* adjust the textures for the sidedefs */
+   ObjectsNeeded (OBJ_SIDEDEFS, 0);
+   if (strncmp (SideDefs[sd1].tex3, "-", WAD_TEX_NAME))
+   {
+      if (!strncmp (SideDefs[sd1].tex1, "-", WAD_TEX_NAME))
+	 strncpy (SideDefs[sd1].tex1, SideDefs[sd1].tex3, WAD_TEX_NAME);
+      strncpy (SideDefs[sd1].tex3, "-", WAD_TEX_NAME);
+   }
+   if (!strncmp (SideDefs[sd1].tex1, "-", WAD_TEX_NAME))
+      strncpy (SideDefs[sd1].tex1, "BIGDOOR2", WAD_TEX_NAME);
+   strncpy (SideDefs[sd2].tex3, "-", WAD_TEX_NAME);
+   UnSelectObject (&ldok, n);
+}
+while (ld1s != NULL)
+{
+   /* give the "door side" flags to the linedef */
+   ObjectsNeeded (OBJ_LINEDEFS, 0);
+   n = ld1s->objnum;
+   LineDefs[n].flags = 0x11;
+   sd1 = LineDefs[n].sidedef1;
+   /* adjust the textures for the sidedef */
+   ObjectsNeeded (OBJ_SIDEDEFS, 0);
+   if (!strncmp (SideDefs[sd1].tex3, "-", WAD_TEX_NAME))
+      strncpy (SideDefs[sd1].tex3, "DOORTRAK", WAD_TEX_NAME);
+   strncpy (SideDefs[sd1].tex1, "-", WAD_TEX_NAME);
+   strncpy (SideDefs[sd1].tex2, "-", WAD_TEX_NAME);
+   UnSelectObject (&ld1s, n);
+}
+/* adjust the ceiling height */
+ObjectsNeeded (OBJ_SECTORS, 0);
+Sectors[sector].ceilh = Sectors[sector].floorh;
+}
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/s_lift.cc	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,219 @@
+/*
+ *	s_lift.cc
+ *	Make lift from sector
+ *	AYM 1998-02-03
+ */
+
+
+/*
+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 "dialog.h"
+#include "levels.h"
+#include "objects.h"
+#include "objid.h"
+#include "selectn.h"
+
+
+/*
+   turn a Sector into a lift: change the linedefs and sidedefs
+*/
+
+void MakeLiftFromSector (int sector) /* SWAP! */
+{
+int    sd1, sd2;
+int    n, s, tag;
+SelPtr ldok, ldflip, ld1s;
+SelPtr sect, curs;
+int    minh, maxh;
+
+ldok = NULL;
+ldflip = NULL;
+ld1s = NULL;
+sect = NULL;
+/* build lists of linedefs that border the Sector */
+for (n = 0; n < NumLineDefs; n++)
+{
+   ObjectsNeeded (OBJ_LINEDEFS, 0);
+   sd1 = LineDefs[n].sidedef1;
+   sd2 = LineDefs[n].sidedef2;
+   if (sd1 >= 0 && sd2 >= 0)
+   {
+      ObjectsNeeded (OBJ_SIDEDEFS, 0);
+      if (SideDefs[sd2].sector == sector)
+      {
+	 SelectObject (&ldok, n); /* already ok */
+	 s = SideDefs[sd1].sector;
+	 if (s != sector && !IsSelected (sect, s))
+	    SelectObject (&sect, s);
+      }
+      if (SideDefs[sd1].sector == sector)
+      {
+	 SelectObject (&ldflip, n); /* will be flipped */
+	 s = SideDefs[sd2].sector;
+	 if (s != sector && !IsSelected (sect, s))
+	    SelectObject (&sect, s);
+      }
+   }
+   else if (sd1 >= 0 && sd2 < 0)
+   {
+      ObjectsNeeded (OBJ_SIDEDEFS, 0);
+      if (SideDefs[sd1].sector == sector)
+	 SelectObject (&ld1s, n); /* wall (one-sided) */
+   }
+}
+/* there must be a way to go on the lift... */
+if (sect == NULL)
+{
+   Beep ();
+   Notify (-1, -1, "The lift must be connected to at least one other Sector.", NULL);
+   ForgetSelection (&ldok);
+   ForgetSelection (&ldflip);
+   ForgetSelection (&ld1s);
+   return;
+}
+/* flip the linedefs that have the wrong orientation */
+if (ldflip != NULL)
+   FlipLineDefs (ldflip, 1);
+/* merge the two selection lists */
+while (ldflip != NULL)
+{
+   if (!IsSelected (ldok, ldflip->objnum))
+      SelectObject (&ldok, ldflip->objnum);
+   UnSelectObject (&ldflip, ldflip->objnum);
+}
+
+/* find a free tag number */
+tag = FindFreeTag ();
+
+/* find the minimum and maximum altitudes */
+ObjectsNeeded (OBJ_SECTORS, 0);
+minh = 32767;
+maxh = -32767;
+for (curs = sect; curs; curs = curs->next)
+   {
+   if (Sectors[curs->objnum].floorh < minh)
+      minh = Sectors[curs->objnum].floorh;
+   if (Sectors[curs->objnum].floorh > maxh)
+      maxh = Sectors[curs->objnum].floorh;
+   }
+ForgetSelection (&sect);
+
+/* change the lift's floor height if necessary */
+if (Sectors[sector].floorh < maxh)
+   Sectors[sector].floorh = maxh;
+
+/* change the lift's ceiling height if necessary */
+if (Sectors[sector].ceilh < maxh + DOOM_PLAYER_HEIGHT)
+   Sectors[sector].ceilh = maxh + DOOM_PLAYER_HEIGHT;
+
+/* assign the new tag number to the lift */
+Sectors[sector].tag = tag;
+
+/* change the linedefs and sidedefs */
+while (ldok != NULL)
+   {
+   /* give the "lower lift" type and flags to the linedef */
+   ObjectsNeeded (OBJ_LINEDEFS, 0);
+   n = ldok->objnum;
+   LineDefs[n].type = 62; /* lower lift (switch) */
+   LineDefs[n].flags = 0x04;
+   LineDefs[n].tag = tag;
+   sd1 = LineDefs[n].sidedef1; /* outside */
+   sd2 = LineDefs[n].sidedef2; /* inside */
+   /* adjust the textures for the sidedef visible from the outside */
+   ObjectsNeeded (OBJ_SIDEDEFS, 0);
+   if (strncmp (SideDefs[sd1].tex3, "-", WAD_TEX_NAME))
+      {
+      if (!strncmp (SideDefs[sd1].tex2, "-", WAD_TEX_NAME))
+	 strncpy (SideDefs[sd1].tex2, SideDefs[sd1].tex3, WAD_TEX_NAME);
+      strncpy (SideDefs[sd1].tex3, "-", WAD_TEX_NAME);
+      }
+   if (!strncmp (SideDefs[sd1].tex2, "-", WAD_TEX_NAME))
+      strncpy (SideDefs[sd1].tex2, "SHAWN2", WAD_TEX_NAME);
+   /* adjust the textures for the sidedef visible from the lift */
+   strncpy (SideDefs[sd2].tex3, "-", WAD_TEX_NAME);
+   s = SideDefs[sd1].sector;
+   ObjectsNeeded (OBJ_SECTORS, 0);
+   if (Sectors[s].floorh > minh)
+      {
+      ObjectsNeeded (OBJ_SIDEDEFS, 0);
+      if (strncmp (SideDefs[sd2].tex3, "-", WAD_TEX_NAME))
+      {
+	 if (!strncmp (SideDefs[sd2].tex2, "-", WAD_TEX_NAME))
+	    strncpy (SideDefs[sd2].tex2, SideDefs[sd1].tex3, WAD_TEX_NAME);
+	 strncpy (SideDefs[sd2].tex3, "-", WAD_TEX_NAME);
+      }
+      if (!strncmp (SideDefs[sd2].tex2, "-", WAD_TEX_NAME))
+	 strncpy (SideDefs[sd2].tex2, "SHAWN2", WAD_TEX_NAME);
+      }
+   else
+      {
+      ObjectsNeeded (OBJ_SIDEDEFS, 0);
+      strncpy (SideDefs[sd2].tex2, "-", WAD_TEX_NAME);
+      }
+   strncpy (SideDefs[sd2].tex3, "-", WAD_TEX_NAME);
+   ObjectsNeeded (OBJ_SECTORS, 0);
+   /* if the ceiling of the sector is lower than that of the lift */
+   if (Sectors[s].ceilh < Sectors[sector].ceilh)
+      {
+      ObjectsNeeded (OBJ_SIDEDEFS, 0);
+      if (strncmp (SideDefs[sd2].tex1, "-", WAD_TEX_NAME))
+	 strncpy (SideDefs[sd2].tex1, default_upper_texture, WAD_TEX_NAME);
+      }
+   ObjectsNeeded (OBJ_SECTORS, 0);
+   /* if the floor of the sector is above the lift */
+   if (Sectors[s].floorh >= Sectors[sector].floorh)
+      {
+      ObjectsNeeded (OBJ_LINEDEFS, 0);
+      LineDefs[n].type = 88; /* lower lift (walk through) */
+      /* flip it, just for fun */
+      curs = NULL;
+      SelectObject (&curs, n);
+      FlipLineDefs (curs, 1);
+      ForgetSelection (&curs);
+      }
+   /* done with this linedef */
+   UnSelectObject (&ldok, n);
+   }
+
+while (ld1s != NULL)
+   {
+   /* these are the lift walls (one-sided) */
+   ObjectsNeeded (OBJ_LINEDEFS, 0);
+   n = ld1s->objnum;
+   LineDefs[n].flags = 0x01;
+   sd1 = LineDefs[n].sidedef1;
+   /* adjust the textures for the sidedef */
+   ObjectsNeeded (OBJ_SIDEDEFS, 0);
+   if (!strncmp (SideDefs[sd1].tex3, "-", WAD_TEX_NAME))
+      strncpy (SideDefs[sd1].tex3, default_middle_texture, WAD_TEX_NAME);
+   strncpy (SideDefs[sd1].tex1, "-", WAD_TEX_NAME);
+   strncpy (SideDefs[sd1].tex2, "-", WAD_TEX_NAME);
+   UnSelectObject (&ld1s, n);
+   }
+}
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/s_linedefs.cc	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,108 @@
+/*
+ *	s_linedefs.cc
+ *	AYM 1998-11-22
+ */
+
+
+/*
+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 "bitvec.h"
+#include "levels.h"
+#include "objects.h"
+#include "objid.h"
+#include "s_linedefs.h"
+#include "selectn.h"
+
+
+/*
+ *	linedefs_of_sector
+ *	Return a bit vector of all linedefs used by the sector.
+ *	It's up to the caller to delete the bit vector after use.
+ */
+bitvec_c *linedefs_of_sector (obj_no_t s)
+{
+bitvec_c *linedefs = new bitvec_c (NumLineDefs);
+for (int n = 0; n < NumLineDefs; n++)
+   if (is_sidedef (LineDefs[n].sidedef1)
+       && SideDefs[LineDefs[n].sidedef1].sector == s
+    || is_sidedef (LineDefs[n].sidedef2)
+       && SideDefs[LineDefs[n].sidedef2].sector == s)
+      linedefs->set (n);
+return linedefs;
+}
+
+
+/*
+ *	linedefs_of_sectors
+ *	Return a bit vector of all linedefs used by the sectors.
+ *	It's up to the caller to delete the bit vector after use.
+ */
+bitvec_c *linedefs_of_sectors (SelPtr list)
+{
+bitvec_c *sectors  = list_to_bitvec (list, NumSectors);
+bitvec_c *linedefs = new bitvec_c (NumLineDefs);
+for (int n = 0; n < NumLineDefs; n++)
+   if (   is_sidedef (LineDefs[n].sidedef1)
+          && sectors->get (SideDefs[LineDefs[n].sidedef1].sector)
+       || is_sidedef (LineDefs[n].sidedef2)
+          && sectors->get (SideDefs[LineDefs[n].sidedef2].sector))
+      linedefs->set (n);
+delete sectors;
+return linedefs;
+}
+
+
+/*
+ *	linedefs_of_sector
+ *	Returns the number of linedefs that face sector <s>
+ *	and, if that number is greater than zero, sets <array>
+ *	to point on a newly allocated array filled with the
+ *	numbers of those linedefs. It's up to the caller to
+ *	delete[] the array after use.
+ */
+int linedefs_of_sector (obj_no_t s, obj_no_t *&array)
+{
+int count = 0;
+for (int n = 0; n < NumLineDefs; n++)
+   if (   is_sidedef (LineDefs[n].sidedef1)
+          && SideDefs[LineDefs[n].sidedef1].sector == s
+       || is_sidedef (LineDefs[n].sidedef2)
+          && SideDefs[LineDefs[n].sidedef2].sector == s)
+      count++;
+if (count > 0)
+   {
+   array = new obj_no_t[count];
+   count = 0;
+   for (int n = 0; n < NumLineDefs; n++)
+      if (   is_sidedef (LineDefs[n].sidedef1)
+	     && SideDefs[LineDefs[n].sidedef1].sector == s
+	  || is_sidedef (LineDefs[n].sidedef2)
+	     && SideDefs[LineDefs[n].sidedef2].sector == s)
+	 array[count++] = n;
+   }
+return count;
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/s_linedefs.h	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,14 @@
+/*
+ *	s_linedefs.h
+ *	AYM 1998-11-22
+ */
+
+
+class bitvec_c;
+
+
+bitvec_c *linedefs_of_sector (obj_no_t s);
+bitvec_c *linedefs_of_sectors (SelPtr list);
+int linedefs_of_sector (obj_no_t s, obj_no_t *&array);
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/s_merge.cc	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,128 @@
+/*
+ *	s_merge.cc
+ *	Merge sectors
+ *	AYM 1998-02-03
+ */
+
+
+/*
+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 "dialog.h"
+#include "levels.h"
+#include "objects.h"
+#include "objid.h"
+#include "selectn.h"
+
+
+/*
+   merge two or more Sectors into one
+*/
+
+void MergeSectors (SelPtr *slist) /* SWAP! */
+{
+SelPtr cur;
+int    n, olds, news;
+
+/* save the first Sector number */
+news = (*slist)->objnum;
+UnSelectObject (slist, news);
+ObjectsNeeded (OBJ_SIDEDEFS, 0);
+
+/* change all SideDefs references to the other Sectors */
+for (cur = *slist; cur; cur = cur->next)
+{
+   olds = cur->objnum;
+   for (n = 0; n < NumSideDefs; n++)
+   {
+      if (SideDefs[n].sector == olds)
+	 SideDefs[n].sector = news;
+   }
+}
+
+/* delete the Sectors */
+DeleteObjects (OBJ_SECTORS, slist);
+
+/* the returned list contains only the first Sector */
+SelectObject (slist, news);
+}
+
+
+
+/*
+   delete one or several two-sided LineDefs and join the two Sectors
+*/
+
+void DeleteLineDefsJoinSectors (SelPtr *ldlist) /* SWAP! */
+{
+SelPtr cur, slist;
+int    sd1, sd2;
+int    s1, s2;
+char   msg[80];
+
+/* first, do the tests for all LineDefs */
+for (cur = *ldlist; cur; cur = cur->next)
+   {
+   ObjectsNeeded (OBJ_LINEDEFS, 0);
+   sd1 = LineDefs[cur->objnum].sidedef1;
+   sd2 = LineDefs[cur->objnum].sidedef2;
+   if (sd1 < 0 || sd2 < 0)
+      {
+      Beep ();
+      sprintf (msg, "ERROR: Linedef #%d has only one side", cur->objnum);
+      Notify (-1, -1, msg, NULL);
+      return;
+      }
+   ObjectsNeeded (OBJ_SIDEDEFS, 0);
+   s1 = SideDefs[sd1].sector;
+   s2 = SideDefs[sd2].sector;
+   if (s1 < 0 || s2 < 0)
+      {
+      Beep ();
+      sprintf (msg, "ERROR: Linedef #%d has two sides, but one", cur->objnum);
+      Notify (-1, -1, msg, "side is not bound to any sector");
+      return;
+      }
+   }
+
+/* then join the Sectors and delete the LineDefs */
+for (cur = *ldlist; cur; cur = cur->next)
+   {
+   ObjectsNeeded (OBJ_LINEDEFS, 0);
+   sd1 = LineDefs[cur->objnum].sidedef1;
+   sd2 = LineDefs[cur->objnum].sidedef2;
+   ObjectsNeeded (OBJ_SIDEDEFS, 0);
+   s1 = SideDefs[sd1].sector;
+   s2 = SideDefs[sd2].sector;
+   slist = NULL;
+   SelectObject (&slist, s2);
+   SelectObject (&slist, s1);
+   MergeSectors (&slist);
+   ForgetSelection (&slist);
+   }
+DeleteObjects (OBJ_LINEDEFS, ldlist);
+}
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/s_misc.cc	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,182 @@
+/*
+ *	s_misc.cc
+ *	Misc. operations on sectors
+ *	AYM 1998-02-03
+ */
+
+
+/*
+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 "entry.h"
+#include "gfx.h"
+#include "levels.h"
+#include "objid.h"
+#include "selectn.h"
+
+
+/*
+   Distribute sector floor heights
+*/
+
+void DistributeSectorFloors (SelPtr obj) /* SWAP! */
+{
+SelPtr cur;
+int    n, num, floor1h, floor2h;
+
+ObjectsNeeded (OBJ_SECTORS, 0);
+
+num = 0;
+for (cur = obj; cur->next; cur = cur->next)
+   num++;
+
+floor1h = Sectors[obj->objnum].floorh;
+floor2h = Sectors[cur->objnum].floorh;
+
+n = 0;
+for (cur = obj; cur; cur = cur->next)
+   {
+   Sectors[cur->objnum].floorh = floor1h + n * (floor2h - floor1h) / num;
+   n++;
+   }
+MadeChanges = 1;
+}
+
+
+
+/*
+   Distribute sector ceiling heights
+*/
+
+void DistributeSectorCeilings (SelPtr obj) /* SWAP! */
+{
+SelPtr cur;
+int    n, num, ceil1h, ceil2h;
+
+ObjectsNeeded (OBJ_SECTORS, 0);
+
+num = 0;
+for (cur = obj; cur->next; cur = cur->next)
+   num++;
+
+ceil1h = Sectors[obj->objnum].ceilh;
+ceil2h = Sectors[cur->objnum].ceilh;
+
+n = 0;
+for (cur = obj; cur; cur = cur->next)
+   {
+   Sectors[cur->objnum].ceilh = ceil1h + n * (ceil2h - ceil1h) / num;
+   n++;
+   }
+MadeChanges = 1;
+}
+
+
+/*
+   Raise or lower sectors
+*/
+
+void RaiseOrLowerSectors (SelPtr obj)
+{
+SelPtr cur;
+int  x0;          // left hand (x) window start
+int  y0;          // top (y) window start
+int  key;         // holds value returned by InputInteger
+int  delta = 0;   // user input for delta
+
+
+HideMousePointer ();
+x0 = (ScrMaxX - 25 - 44 * FONTW) / 2;
+y0 = (ScrMaxY - 7 * FONTH) / 2;
+DrawScreenBox3D (x0, y0, x0 + 25 + 44 * FONTW, y0 + 7 * FONTH);
+set_colour (WHITE);
+DrawScreenText (x0+10, y0 + FONTH,     "Enter number of units to raise the ceilings");
+DrawScreenText (x0+10, y0 + 2 * FONTH, "and floors of selected sectors by.");
+DrawScreenText (x0+10, y0 + 3 * FONTH, "A negative number lowers them.");
+while (1)
+  {
+  key = InputInteger (x0+10, y0 + 5 * FONTH, &delta, -32768, 32767);
+  if (key == YK_RETURN || key == YK_ESC)
+    break;
+  Beep ();
+  }
+ShowMousePointer ();
+if (key == YK_ESC)
+  return;
+
+ObjectsNeeded (OBJ_SECTORS, 0);
+for (cur = obj; cur != NULL; cur = cur->next)
+  {
+  Sectors[cur->objnum].ceilh += delta;
+  Sectors[cur->objnum].floorh += delta;
+  }
+MadeChanges = 1;
+}
+
+
+/*
+   Brighten or darken sectors
+*/
+
+void BrightenOrDarkenSectors (SelPtr obj)
+{
+SelPtr cur;
+int  x0;          // left hand (x) window start
+int  y0;          // top (y) window start
+int  key;         // holds value returned by InputInteger
+int  delta = 0;   // user input for delta
+
+
+HideMousePointer ();
+x0 = (ScrMaxX - 25 - 44 * FONTW) / 2;
+y0 = (ScrMaxY - 7 * FONTH) / 2;
+DrawScreenBox3D (x0, y0, x0 + 25 + 44 * FONTW, y0 + 7 * FONTH);
+set_colour (WHITE);
+DrawScreenText (x0+10, y0 + FONTH,     "Enter number of units to brighten");
+DrawScreenText (x0+10, y0 + 2 * FONTH, "the selected sectors by.");
+DrawScreenText (x0+10, y0 + 3 * FONTH, "A negative number darkens them.");
+while (1)
+  {
+  key = InputInteger (x0+10, y0 + 5 * FONTH, &delta, -255, 255);
+  if (key == YK_RETURN || key == YK_ESC)
+    break;
+  Beep ();
+  }
+ShowMousePointer ();
+if (key == YK_ESC)
+  return;
+
+ObjectsNeeded (OBJ_SECTORS, 0);
+for (cur = obj; cur != NULL; cur = cur->next)
+  {
+  int light;
+  light = Sectors[cur->objnum].light + delta;
+  light = y_max (light, 0);
+  light = y_min (light, 255);
+  Sectors[cur->objnum].light = light;
+  }
+MadeChanges = 1;
+}
+
+/* end of file */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/s_prop.cc	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,262 @@
+/*
+ *	s_prop.cc
+ *	Sector properties
+ *	Some of this was originally in editobj.c. It was moved here to
+ *	improve overlay granularity (therefore memory consumption).
+ *	AYM 1998-02-07
+ */
+
+
+/*
+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 "entry.h"
+#include "flats.h"
+#include "game.h"
+#include "gfx.h"
+#include "levels.h"
+#include "menudata.h"
+#include "objid.h"
+#include "oldmenus.h"
+#include "selectn.h"
+
+
+class Menu_data_st : public Menu_data
+{
+  public :
+    Menu_data_st (al_llist_t *list);
+    virtual size_t nitems () const;
+    virtual const char *operator[] (size_t n) const;
+
+  private :
+    mutable char buf[100];
+    al_llist_t *list;
+};
+
+
+/*
+ *	Menu_data_st::Menu_data_st - ctor
+ */
+Menu_data_st::Menu_data_st (al_llist_t *list) : list (list)
+{
+  al_lrewind (this->list);
+}
+
+
+/*
+ *	Menu_data_st::nitems - return the number of items
+ */
+size_t Menu_data_st::nitems () const
+{
+  return al_lcount (list);
+}
+
+
+/*
+ *	Menu_data_st::operator[] - return the nth item
+ */
+const char *Menu_data_st::operator[] (size_t n) const
+{
+  if (al_lseek (list, n, SEEK_SET) != 0)
+  {
+    sprintf (buf, "BUG: al_lseek(%p, %lu): %s",
+      (void *) list, 
+      (unsigned long) n,
+      al_astrerror (al_aerrno));
+    return buf;
+  }
+  const stdef_t *ptr = (const stdef_t *) al_lptr (list);
+  if (ptr == NULL)
+    sprintf (buf, "BUG: al_lptr(%p): %s",
+      (void *) list,
+      al_astrerror (al_aerrno));
+  else
+    sprintf (buf, "%2d - %.70s", ptr->number, ptr->longdesc);
+  return buf;
+}
+
+
+/*
+ *	SectorProperties
+ *	Sector properties "dialog"
+ */
+void SectorProperties (int x0, int y0, SelPtr obj)
+{
+  char  *menustr[30];
+  char   texname[WAD_FLAT_NAME + 1];
+  int    n, val;
+  SelPtr cur;
+  int    subwin_y0;
+
+  for (n = 0; n < 8; n++)
+    menustr[n] = (char *) GetMemory (60);
+  sprintf (menustr[7], "Edit sector #%d", obj->objnum);
+  sprintf (menustr[0], "Change floor height     (Current: %d)",
+	  Sectors[obj->objnum].floorh);
+  sprintf (menustr[1], "Change ceiling height   (Current: %d)",
+	  Sectors[obj->objnum].ceilh);
+  sprintf (menustr[2], "Change floor texture    (Current: %.*s)",
+	  (int) WAD_FLAT_NAME, Sectors[obj->objnum].floort);
+  sprintf (menustr[3], "Change ceiling texture  (Current: %.*s)",
+	  (int) WAD_FLAT_NAME, Sectors[obj->objnum].ceilt);
+  sprintf (menustr[4], "Change light level      (Current: %d)",
+	  Sectors[obj->objnum].light);
+  sprintf (menustr[5], "Change type             (Current: %d)",
+	  Sectors[obj->objnum].special);
+  sprintf (menustr[6], "Change linedef tag      (Current: %d)",
+	  Sectors[obj->objnum].tag);
+  val = vDisplayMenu (x0, y0, menustr[7],
+    menustr[0], YK_, 0,
+    menustr[1], YK_, 0,
+    menustr[2], YK_, 0,
+    menustr[3], YK_, 0,
+    menustr[4], YK_, 0,
+    menustr[5], YK_, 0,
+    menustr[6], YK_, 0,
+    NULL);
+  for (n = 0; n < 8; n++)
+    FreeMemory (menustr[n]);
+  subwin_y0 = y0 + BOX_BORDER + (2 + val) * FONTH;
+  switch (val)
+  {
+    case 1:
+      val = InputIntegerValue (x0 + 42, subwin_y0, -32768, 32767,
+	Sectors[obj->objnum].floorh);
+      if (val != IIV_CANCEL)
+      {
+	for (cur = obj; cur; cur = cur->next)
+	  Sectors[cur->objnum].floorh = val;
+	MadeChanges = 1;
+      }
+      break;
+
+    case 2:
+      val = InputIntegerValue (x0 + 42, subwin_y0, -32768, 32767,
+	Sectors[obj->objnum].ceilh);
+      if (val != IIV_CANCEL)
+      {
+	for (cur = obj; cur; cur = cur->next)
+	  Sectors[cur->objnum].ceilh = val;
+	MadeChanges = 1;
+      }
+      break;
+
+    case 3:
+      {
+	*texname = '\0';
+	strncat (texname, Sectors[obj->objnum].floort, WAD_FLAT_NAME);
+	ObjectsNeeded (0);
+	char **flat_names =
+	  (char **) GetMemory (NumFTexture * sizeof *flat_names);
+	for (size_t n = 0; n < NumFTexture; n++)
+	  flat_names[n] = flat_list[n].name;
+	ChooseFloorTexture (x0 + 42, subwin_y0, "Choose a floor texture",
+	  NumFTexture, flat_names, texname);
+	FreeMemory (flat_names);
+	ObjectsNeeded (OBJ_SECTORS, 0);
+	if (strlen (texname) > 0)
+	{
+	  for (cur = obj; cur; cur = cur->next)
+	    strncpy (Sectors[cur->objnum].floort, texname, WAD_FLAT_NAME);
+	  MadeChanges = 1;
+	}
+	break;
+      }
+
+    case 4:
+      {
+      *texname = '\0';
+      strncat (texname, Sectors[obj->objnum].ceilt, WAD_FLAT_NAME);
+      ObjectsNeeded (0);
+      char **flat_names =
+	(char **) GetMemory (NumFTexture * sizeof *flat_names);
+      for (size_t n = 0; n < NumFTexture; n++)
+	flat_names[n] = flat_list[n].name;
+      ChooseFloorTexture (x0 + 42, subwin_y0, "Choose a ceiling texture",
+	NumFTexture, flat_names, texname);
+      FreeMemory (flat_names);
+      ObjectsNeeded (OBJ_SECTORS, 0);
+      if (strlen (texname) > 0)
+      {
+	for (cur = obj; cur; cur = cur->next)
+	  strncpy (Sectors[cur->objnum].ceilt, texname, WAD_FLAT_NAME);
+	MadeChanges = 1;
+      }
+      break;
+      }
+
+    case 5:
+      val = InputIntegerValue (x0 + 42, subwin_y0, 0, 255,
+	Sectors[obj->objnum].light);
+      if (val != IIV_CANCEL)
+      {
+	for (cur = obj; cur; cur = cur->next)
+	  Sectors[cur->objnum].light = val;
+	MadeChanges = 1;
+      }
+      break;
+
+    case 6:
+      {
+	val = 0;
+	Menu_data_st menudata (stdef);
+	if (DisplayMenuList (x0 + 42, subwin_y0, "Select type", menudata, &val)
+	  < 0)
+	  break;
+	// KLUDGE last element of stdef means "enter value"
+	if (val == al_lcount (stdef) - 1)
+	{
+	  val = InputIntegerValue (x0 + 84,
+	    subwin_y0 + BOX_BORDER + (3 + val) * FONTH,
+	    -32768, 32767, 0);
+	  if (val == IIV_CANCEL)  // [Esc]
+	    break;
+	}
+	else
+	{
+	  if (al_lseek (stdef, val, SEEK_SET))
+	    fatal_error ("%s SP1 (%s)\n",
+	      msg_unexpected, al_astrerror (al_aerrno));
+	  val = CUR_STDEF->number;
+	}
+	for (cur = obj; cur; cur = cur->next)
+	  Sectors[cur->objnum].special = val;
+	MadeChanges = 1;
+	break;
+      }
+
+    case 7:
+      val = InputIntegerValue (x0 + 42, subwin_y0, -32768, 32767,
+	Sectors[obj->objnum].tag);
+      if (val != IIV_CANCEL)
+      {
+	for (cur = obj; cur; cur = cur->next)
+	  Sectors[cur->objnum].tag = val;
+	MadeChanges = 1;
+      }
+      break;
+  }
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/s_slice.cc	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,307 @@
+/*
+ *	s_slice.cc
+ *	Cut a slice out of a sector
+ *	AYM 2001-09-11
+ */
+
+
+/*
+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 <map>
+#include "dialog.h"
+#include "levels.h"
+#include "objects.h"
+#include "objid.h"
+#include "s_slice.h"
+
+
+class Secref			// Reference to a sector
+{
+  public :
+    Secref () : linedef1 ('\0'), linedef2 ('\0') { }
+    char linedef1;
+    char linedef2;
+};
+
+
+/*
+ *	sector_slice - cut a slice out of a sector
+ */
+void sector_slice (obj_no_t linedef1, obj_no_t linedef2)
+{
+  /* We have between 0 and 4 sidedefs. We need to make sure that
+     there are exactly 2 that face the same sector and that they
+     belong to different linedefs.
+
+     If a linedef has more than one sidedef that faces the same
+     sector, we can't decide which one faces the other linedef.
+     Well, we can but it's hard for a dummy like me.
+
+     The problem is the same if the linedefs have two sectors in
+     common. Consider the following setup :
+		____________________________________
+	       |                                    |
+	       |              sector 0              |
+	       |      ________________________      |
+	       |     |                        |     |
+	       |     |        sector 1        |     |
+	       |     |      ____________      |     |
+	       |     |     |            |     |     |
+	       |     |     |  sector 0  |-L1  |-L2  |
+	       |     |     |____________|     |     |
+	       |     |                        |     |
+	       |     |                        |     |
+	       |     |________________________|     |
+	       |                                    |
+	       |                                    |
+	       |____________________________________|
+
+     How do you decide to which vertex of L2 should the start
+     vertex of L1 be linked ? */
+
+  if (! is_linedef (linedef1))		// Paranoia
+  {
+    char buf[100];
+    y_snprintf (buf, sizeof buf,
+	"First argument is not a valid linedef number");
+    Notify (-1, -1, buf, 0);
+    return;
+  }
+
+  if (! is_linedef (linedef2))		// Paranoia
+  {
+    char buf[100];
+    y_snprintf (buf, sizeof buf,
+	"Second argument is not a valid linedef number");
+    Notify (-1, -1, buf, 0);
+    return;
+  }
+
+  if (linedef1 == linedef2)
+  {
+    char buf[100];
+    y_snprintf (buf, sizeof buf, "Both arguments are the same linedef");
+    Notify (-1, -1, buf, 0);
+    return;
+  }
+
+  obj_no_t l1start = LineDefs[linedef1].start;
+  obj_no_t l1end   = LineDefs[linedef1].end;
+  obj_no_t l2start = LineDefs[linedef2].start;
+  obj_no_t l2end   = LineDefs[linedef2].end;
+
+  if (l1start == l2start && l1end == l2end
+    || l1start == l2end && l1end == l2start)
+  {
+    char buf[100];
+    y_snprintf (buf, sizeof buf, "Linedefs %d and %d are superimposed",
+        int (linedef1), int (linedef2));
+    Notify (-1, -1, buf, 0);
+    return;
+  }
+
+  obj_no_t l1sdr = LineDefs[linedef1].sidedef1;
+  obj_no_t l1sdl = LineDefs[linedef1].sidedef2;
+  obj_no_t l2sdr = LineDefs[linedef2].sidedef1;
+  obj_no_t l2sdl = LineDefs[linedef2].sidedef2;
+
+  obj_no_t l1sr = is_sidedef (l1sdr) ? SideDefs[l1sdr].sector : OBJ_NO_NONE;
+  obj_no_t l1sl = is_sidedef (l1sdl) ? SideDefs[l1sdl].sector : OBJ_NO_NONE;
+  obj_no_t l2sr = is_sidedef (l2sdr) ? SideDefs[l2sdr].sector : OBJ_NO_NONE;
+  obj_no_t l2sl = is_sidedef (l2sdl) ? SideDefs[l2sdl].sector : OBJ_NO_NONE;
+
+  if (is_sector (l1sr) && is_sector (l1sl) && l1sr == l1sl)
+  {
+    char buf[100];
+    y_snprintf (buf, sizeof buf, "Linedef %d has both sides in the same sector",
+	int (linedef1));
+    Notify (-1, -1, buf, 0);
+    return;
+  }
+
+  if (is_sector (l2sr) && is_sector (l2sl) && l2sr == l2sl)
+  {
+    char buf[100];
+    y_snprintf (buf, sizeof buf, "Linedef %d has both sides in the same sector",
+	int (linedef2));
+    Notify (-1, -1, buf, 0);
+    return;
+  }
+
+  // Verify that the linedefs have exactly one sector in common
+  typedef std::map<obj_no_t, Secref> secref_list_t;
+  secref_list_t secref;
+  if (is_sector (l1sr))
+    secref[l1sr].linedef1 = 'r';
+  if (is_sector (l1sl))
+    secref[l1sl].linedef1 = 'l';
+  if (is_sector (l2sr))
+    secref[l2sr].linedef2 = 'r';
+  if (is_sector (l2sl))
+    secref[l2sl].linedef2 = 'l';
+  obj_no_t sector;
+  int count = 0;
+  for (secref_list_t::iterator i = secref.begin (); i != secref.end (); i++)
+  {
+    if (i->second.linedef1 != '\0' && i->second.linedef2 != '\0')
+    {
+      sector = i->first;
+      count++;
+    }
+  }
+  if (count < 1)
+  {
+    char buf[100];
+    y_snprintf (buf, sizeof buf,
+	"Linedefs %d and %d don't face the same sector",
+	int (linedef1), int (linedef2));
+    Notify (-1, -1, buf, 0);
+    return;
+  }
+  if (count > 1)
+  {
+    char buf[100];
+    y_snprintf (buf, sizeof buf,
+	"Linedefs %d and %d have more than one sector in common",
+	int (linedef1), int (linedef2));
+    Notify (-1, -1, buf, 0);
+    return;
+  }
+
+  // Insert new sector between linedefs
+  obj_no_t la0, la1;		// Start and end of the first linedef (the
+				// one that goes from linedef1 to linedef2)
+  obj_no_t lb0, lb1;		// Start and end of the second linedef (the
+				// one that goes from linedef2 to linedef1)
+  char side = secref[sector].linedef1;
+  if (side == 'r')
+  {
+    la0 = l1end;
+    lb1 = l1start;
+  }
+  else if (side == 'l')
+  {
+    la0 = l1start;
+    lb1 = l1end;
+  }
+  else					// Can't happen
+  {
+    nf_bug ("sector %d: linedef1 = %02Xh", int (sector), side);
+    return;
+  }
+
+  side = secref[sector].linedef2;
+  if (side == 'r')
+  {
+    la1 = l2start;
+    lb0 = l2end;
+  }
+  else if (side == 'l')
+  {
+    la1 = l2end;
+    lb0 = l2start;
+  }
+  else					// Can't happen
+  {
+    nf_bug ("sector %d: linedef2 = %02Xh", int (sector), side);
+    return;
+  }
+
+  // Verify that there's no linedef already between linedef1 and linedef2
+  {
+    for (int n = 0; n < NumLineDefs; n++)
+    {
+      if (n == linedef1 || n == linedef2)
+	continue;
+      if (LineDefs[n].start == la0 && LineDefs[n].end == la1
+       || LineDefs[n].start == la1 && LineDefs[n].end == la0
+       || LineDefs[n].start == lb0 && LineDefs[n].end == lb1
+       || LineDefs[n].start == lb1 && LineDefs[n].end == lb0)
+      {
+	char buf[100];
+	y_snprintf (buf, sizeof buf,
+	    "A linedef already exists between linedefs %d and %d (linedef %d)",
+	    int (linedef1), int (linedef2), int (n));
+	Notify (-1, -1, buf, 0);
+	return;
+      }
+    }
+  }
+  
+  // Create new sector
+  InsertObject (OBJ_SECTORS, sector, 0, 0);
+
+  // Create new linedef from linedef1 to linedef2
+  if (la0 != la1)
+  {
+    InsertObject (OBJ_LINEDEFS, -1, 0, 0);
+    LineDefs[NumLineDefs - 1].start = la0;
+    LineDefs[NumLineDefs - 1].end   = la1;
+    LineDefs[NumLineDefs - 1].flags = 4;
+    InsertObject (OBJ_SIDEDEFS, -1, 0, 0);		// Right sidedef
+    SideDefs[NumSideDefs - 1].sector = NumSectors - 1;	// Redundant
+    strncpy (SideDefs[NumSideDefs - 1].tex3, "-", 8);
+    LineDefs[NumLineDefs - 1].sidedef1 = NumSideDefs - 1;
+    InsertObject (OBJ_SIDEDEFS, -1, 0, 0);		// Left sidedef
+    SideDefs[NumSideDefs - 1].sector = sector;
+    strncpy (SideDefs[NumSideDefs - 1].tex3, "-", 8);
+    LineDefs[NumLineDefs - 1].sidedef2 = NumSideDefs - 1;
+  }
+
+  // Create new linedef from linedef2 to linedef1
+  if (lb0 != lb1)
+  {
+    InsertObject (OBJ_LINEDEFS, -1, 0, 0);
+    LineDefs[NumLineDefs - 1].start = lb0;
+    LineDefs[NumLineDefs - 1].end   = lb1;
+    LineDefs[NumLineDefs - 1].flags = 4;
+    InsertObject (OBJ_SIDEDEFS, -1, 0, 0);		// Right sidedef
+    SideDefs[NumSideDefs - 1].sector = NumSectors - 1;	// Redundant
+    strncpy (SideDefs[NumSideDefs - 1].tex3, "-", 8);
+    LineDefs[NumLineDefs - 1].sidedef1 = NumSideDefs - 1;
+    InsertObject (OBJ_SIDEDEFS, -1, 0, 0);		// Left sidedef
+    SideDefs[NumSideDefs - 1].sector = sector;
+    strncpy (SideDefs[NumSideDefs - 1].tex3, "-", 8);
+    LineDefs[NumLineDefs - 1].sidedef2 = NumSideDefs - 1;
+  }
+
+  // Adjust sector references for linedef1
+  side = secref[sector].linedef1;
+  if (side == 'r')
+    SideDefs[LineDefs[linedef1].sidedef1].sector = NumSectors - 1;
+  else if (side == 'l')
+    SideDefs[LineDefs[linedef1].sidedef2].sector = NumSectors - 1;
+
+  // Adjust sector references for linedef2
+  side = secref[sector].linedef2;
+  if (side == 'r')
+    SideDefs[LineDefs[linedef2].sidedef1].sector = NumSectors - 1;
+  else if (side == 'l')
+    SideDefs[LineDefs[linedef2].sidedef2].sector = NumSectors - 1;
+
+  MadeChanges = 1;
+  MadeMapChanges = 1;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/s_slice.h	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,14 @@
+/*
+ *	s_slice.h
+ *	AYM 2001-09-13
+ */
+
+
+#ifndef YH_S_SLICE  /* DO NOT INSERT ANYTHING BEFORE THIS LINE */
+#define YH_S_SLICE
+
+
+void sector_slice (obj_no_t linedef1, obj_no_t linedef2);
+
+
+#endif  /* DO NOT ADD ANYTHING AFTER THIS LINE */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/s_split.cc	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,233 @@
+/*
+ *	s_split.cc
+ *	Split sectors
+ *	AYM 1998-02-03
+ */
+
+
+/*
+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 "dialog.h"
+#include "levels.h"
+#include "objects.h"
+#include "objid.h"
+#include "s_linedefs.h"
+#include "selectn.h"
+#include "x_hover.h"
+
+
+/*
+   split a sector in two, adding a new linedef between the two vertices
+*/
+
+void SplitSector (int vertex1, int vertex2) /* SWAP! */
+{
+SelPtr llist;
+int    curv, s, l, sd;
+char   msg1[80], msg2[80];
+
+/* AYM 1998-08-09 : FIXME : I'm afraid this test is not relevant
+   if the sector contains subsectors. I should ask Jim (Flynn),
+   he did something about that in DETH. */
+/* Check if there is a sector between the two vertices (in the middle) */
+Objid o;
+GetCurObject (o, OBJ_SECTORS,
+	      (Vertices[vertex1].x + Vertices[vertex2].x) / 2,
+	      (Vertices[vertex1].y + Vertices[vertex2].y) / 2);
+s = o.num;
+if (s < 0)
+   {
+   Beep ();
+   sprintf (msg1, "There is no sector between vertex #%d and vertex #%d",
+     vertex1, vertex2);
+   Notify (-1, -1, msg1, NULL);
+   return;
+   }
+
+/* Check if there is a closed path from <vertex1> to <vertex2>,
+   along the edge of sector <s>. To make it faster, I scan only
+   the set of linedefs that face sector <s>. */
+ObjectsNeeded (OBJ_LINEDEFS, OBJ_SIDEDEFS, 0);
+obj_no_t *ld_numbers;
+int nlinedefs = linedefs_of_sector (s, ld_numbers);
+if (nlinedefs < 1)  // Can't happen
+   {
+   nf_bug ("SplitSector: no linedef for sector %d\n", s);
+   return;
+   }
+llist = NULL;
+curv = vertex1;
+while (curv != vertex2)
+   {
+   printf ("%d\n", curv);
+   int n;
+   for (n = 0; n < nlinedefs; n++)
+      {
+      if (IsSelected (llist, ld_numbers[n]))
+	 continue;  // Already been there
+      const LDPtr ld = LineDefs + ld_numbers[n];
+      if (ld->start == curv
+	  && is_sidedef (ld->sidedef1) && SideDefs[ld->sidedef1].sector == s)
+         {
+	 curv = ld->end;
+	 SelectObject (&llist, ld_numbers[n]);
+	 break;
+         }
+      if (ld->end == curv
+	  && is_sidedef (ld->sidedef2) && SideDefs[ld->sidedef2].sector == s)
+	 {
+	 curv = ld->start;
+	 SelectObject (&llist, ld_numbers[n]);
+	 break;
+         }
+      }
+   if (n >= nlinedefs)
+      {
+      Beep ();
+      sprintf (msg1, "Cannot find a closed path from vertex #%d to vertex #%d",
+        vertex1, vertex2);
+      if (curv == vertex1)
+	 sprintf (msg2, "There is no sidedef starting from vertex #%d"
+	   " on sector #%d", vertex1, s);
+      else
+	 sprintf (msg2, "Check if sector #%d is closed"
+	   " (cannot go past vertex #%d)", s, curv);
+      Notify (-1, -1, msg1, msg2);
+      ForgetSelection (&llist);
+      delete[] ld_numbers;
+      return;
+      }
+   if (curv == vertex1)
+      {
+      Beep ();
+      sprintf (msg1, "Vertex #%d is not on the same sector (#%d)"
+        " as vertex #%d", vertex2, s, vertex1);
+      Notify (-1, -1, msg1, NULL);
+      ForgetSelection (&llist);
+      delete[] ld_numbers;
+      return;
+      }
+   }
+delete[] ld_numbers;
+/* now, the list of linedefs for the new sector is in llist */
+
+/* add the new sector, linedef and sidedefs */
+InsertObject (OBJ_SECTORS, s, 0, 0);
+InsertObject (OBJ_LINEDEFS, -1, 0, 0);
+LineDefs[NumLineDefs - 1].start = vertex1;
+LineDefs[NumLineDefs - 1].end = vertex2;
+LineDefs[NumLineDefs - 1].flags = 4;
+InsertObject (OBJ_SIDEDEFS, -1, 0, 0);
+SideDefs[NumSideDefs - 1].sector = s;
+strncpy (SideDefs[NumSideDefs - 1].tex3, "-", WAD_TEX_NAME);
+InsertObject (OBJ_SIDEDEFS, -1, 0, 0);
+strncpy (SideDefs[NumSideDefs - 1].tex3, "-", WAD_TEX_NAME);
+ObjectsNeeded (OBJ_LINEDEFS, OBJ_SIDEDEFS, 0);
+LineDefs[NumLineDefs - 1].sidedef1 = NumSideDefs - 2;
+LineDefs[NumLineDefs - 1].sidedef2 = NumSideDefs - 1;
+
+/* bind all linedefs in llist to the new sector */
+while (llist)
+{
+   sd = LineDefs[llist->objnum].sidedef1;
+   if (sd < 0 || SideDefs[sd].sector != s)
+      sd = LineDefs[llist->objnum].sidedef2;
+   SideDefs[sd].sector = NumSectors - 1;
+   UnSelectObject (&llist, llist->objnum);
+}
+
+/* second check... useful for sectors within sectors */
+ObjectsNeeded (OBJ_LINEDEFS, OBJ_SIDEDEFS, 0);
+for (l = 0; l < NumLineDefs; l++)
+{
+   sd = LineDefs[l].sidedef1;
+   if (sd >= 0 && SideDefs[sd].sector == s)
+   {
+      curv = GetOppositeSector (l, 1);
+      ObjectsNeeded (OBJ_LINEDEFS, OBJ_SIDEDEFS, 0);
+      if (curv == NumSectors - 1)
+	 SideDefs[sd].sector = NumSectors - 1;
+   }
+   sd = LineDefs[l].sidedef2;
+   if (sd >= 0 && SideDefs[sd].sector == s)
+   {
+      curv = GetOppositeSector (l, 0);
+      ObjectsNeeded (OBJ_LINEDEFS, OBJ_SIDEDEFS, 0);
+      if (curv == NumSectors - 1)
+	 SideDefs[sd].sector = NumSectors - 1;
+   }
+}
+
+MadeChanges = 1;
+MadeMapChanges = 1;
+}
+
+
+
+/*
+   split two linedefs, then split the sector and add a new linedef between the new vertices
+*/
+
+void SplitLineDefsAndSector (int linedef1, int linedef2) /* SWAP! */
+{
+SelPtr llist;
+int    s1, s2, s3, s4;
+char   msg[80];
+
+/* check if the two linedefs are adjacent to the same sector */
+ObjectsNeeded (OBJ_LINEDEFS, 0);
+s1 = LineDefs[linedef1].sidedef1;
+s2 = LineDefs[linedef1].sidedef2;
+s3 = LineDefs[linedef2].sidedef1;
+s4 = LineDefs[linedef2].sidedef2;
+ObjectsNeeded (OBJ_SIDEDEFS, 0);
+if (s1 >= 0)
+   s1 = SideDefs[s1].sector;
+if (s2 >= 0)
+   s2 = SideDefs[s2].sector;
+if (s3 >= 0)
+   s3 = SideDefs[s3].sector;
+if (s4 >= 0)
+   s4 = SideDefs[s4].sector;
+if ((s1 < 0 || (s1 != s3 && s1 != s4)) && (s2 < 0 || (s2 != s3 && s2 != s4)))
+{
+   Beep ();
+   sprintf (msg, "Linedefs #%d and #%d are not adjacent to the same sector",
+     linedef1, linedef2);
+   Notify (-1, -1, msg, NULL);
+   return;
+}
+/* split the two linedefs and create two new vertices */
+llist = NULL;
+SelectObject (&llist, linedef1);
+SelectObject (&llist, linedef2);
+SplitLineDefs (llist);
+ForgetSelection (&llist);
+/* split the sector and create a linedef between the two vertices */
+SplitSector (NumVertices - 1, NumVertices - 2);
+}
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/s_swapf.cc	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,49 @@
+/*
+ *	s_swapf.cc
+ *	Swap floor and ceiling flats of sectors
+ *	AYM 2000-08-12
+ */
+
+
+/*
+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 "levels.h"
+#include "selectn.h"
+
+
+void swap_flats (SelPtr list)
+{
+  for (SelPtr cur = list; cur != NULL; cur = cur->next)
+  {
+    wad_flat_name_t tmp;
+    struct Sector *s = Sectors + cur->objnum;
+
+    memcpy (tmp,       s->floort, sizeof tmp);
+    memcpy (s->floort, s->ceilt,  sizeof s->floort);
+    memcpy (s->ceilt,  tmp,       sizeof s->ceilt);
+    MadeChanges = 1;
+  }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/s_swapf.h	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,9 @@
+/*
+ *	s_swapf.h
+ *	Swap floor and ceiling flats of sectors
+ *	AYM 2000-08-12
+ */
+
+
+void swap_flats (SelPtr list);
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/s_vertices.cc	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,91 @@
+/*
+ *	s_vertices.cc
+ *	AYM 1998-11-22
+ */
+
+
+/*
+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 "bitvec.h"
+#include "l_vertices.h"
+#include "levels.h"
+#include "objid.h"
+#include "s_linedefs.h"
+#include "s_vertices.h"
+
+
+/*
+ *	bv_vertices_of_sector
+ *	Return a bit vector of all vertices used by a sector.
+ *	It's up to the caller to delete the bit vector after use.
+ */
+bitvec_c *bv_vertices_of_sector (obj_no_t s)
+{
+  bitvec_c *linedefs = linedefs_of_sector (s);
+  bitvec_c *vertices = bv_vertices_of_linedefs (linedefs);
+  delete linedefs;
+  return vertices;
+}
+
+
+/*
+ *	bv_vertices_of_sectors
+ *	Return a bit vector of all vertices used by the sectors.
+ *	It's up to the caller to delete the bit vector after use.
+ */
+bitvec_c *bv_vertices_of_sectors (SelPtr list)
+{
+  bitvec_c *linedefs;  // Linedefs used by the sectors
+  bitvec_c *vertices;  // Vertices used by the linedefs
+
+  linedefs = linedefs_of_sectors (list);
+  vertices = bv_vertices_of_linedefs (linedefs);
+  delete linedefs;
+  return vertices;
+}
+
+
+/*
+ *	list_vertices_of_sectors
+ *	Return a list of all vertices used by the sectors.
+ *	It's up to the caller to delete the list after use.
+ */
+SelPtr list_vertices_of_sectors (SelPtr list)
+{
+  bitvec_c *vertices_bitvec;
+  SelPtr vertices_list = 0;
+  size_t n;
+
+  vertices_bitvec = bv_vertices_of_sectors (list);
+  for (n = 0; n < vertices_bitvec->nelements (); n++)
+  {
+    if (vertices_bitvec->get (n))
+      SelectObject (&vertices_list, n);
+  }
+  delete vertices_bitvec;
+  return vertices_list;
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/s_vertices.h	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,14 @@
+/*
+ *	s_vertices.h
+ *	AYM 1998-11-22
+ */
+
+
+class bitvec_c;
+#include "selectn.h"
+
+
+bitvec_c *bv_vertices_of_sector (obj_no_t s);
+bitvec_c *bv_vertices_of_sectors (SelPtr list);
+SelPtr list_vertices_of_sectors (SelPtr list);
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/sanity.cc	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,117 @@
+/*
+ *	sanity.cc
+ *	Sanity checks
+ *	AYM 1998-06-14
+ */
+
+
+/*
+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 "sanity.h"
+#include "wstructs.h"
+
+
+/*
+ *	check_types
+ *
+ *	Sanity checks about the sizes and properties of certain types.
+ *	Useful when porting.
+ */
+
+#define assert_size(type,size)						\
+  do									\
+  {									\
+    if (sizeof (type) != size)						\
+      fatal_error ("sizeof " #type " is %d (should be " #size ")",	\
+	(int) sizeof (type));						\
+  }									\
+  while (0)
+   
+#define assert_wrap(type,high,low)					\
+  do									\
+  {									\
+    type n = high;							\
+    if (++n != low)							\
+      fatal_error ("Type " #type " wraps around to %lu (should be " #low ")",\
+	(unsigned long) n);						\
+  }									\
+  while (0)
+
+void check_types ()
+{
+  assert_size (u8,  1);
+  assert_size (i8,  1);
+  assert_size (u16, 2);
+  assert_size (i16, 2);
+  assert_size (u32, 4);
+  assert_size (i32, 4);
+  assert_size (struct LineDef, 14);
+  assert_size (struct Sector,  26);
+  assert_size (struct SideDef, 30);
+  assert_size (struct Thing,   10);
+  assert_size (struct Vertex,   4);
+  assert_wrap (u8,          255,           0);
+  assert_wrap (i8,          127,        -128);
+  assert_wrap (u16,       65535,           0);
+  assert_wrap (i16,       32767,      -32768);
+  assert_wrap (u32, 4294967295u,           0);
+  assert_wrap (i32,  2147483647, -2147483648);
+}
+
+
+/*
+ *	check_charset
+ *
+ *	If this test fails on your platform, send me a postcard
+ *	from your galaxy.
+ */
+void check_charset ()
+{
+  /* Always false, unless your platform uses a
+     character set even worse than EBCDIC (yet
+     unseen). */
+  if (   '0' + 1 != '1'
+      || '1' + 1 != '2'
+      || '2' + 1 != '3'
+      || '3' + 1 != '4'
+      || '4' + 1 != '5'
+      || '5' + 1 != '6'
+      || '6' + 1 != '7'
+      || '7' + 1 != '8'
+      || '8' + 1 != '9'
+      || 'a' + 1 != 'b'
+      || 'b' + 1 != 'c'
+      || 'c' + 1 != 'd'
+      || 'd' + 1 != 'e'
+      || 'e' + 1 != 'f'
+      || 'A' + 1 != 'B'
+      || 'B' + 1 != 'C'
+      || 'C' + 1 != 'D'
+      || 'D' + 1 != 'E'
+      || 'E' + 1 != 'F')
+    fatal_error ("This platform uses a terminally broken character set");
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/sanity.h	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,10 @@
+/*
+ *	sanity.h
+ *	AYM 1998-11-25
+ */
+
+
+void check_types ();
+void check_charset ();
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/scrnshot.cc	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,116 @@
+/*
+ *	scrnshot.cc
+ *	This module contains the function ScreenShot() which is called
+ *	whenever you press shift-F1 in edit mode. It is only a wrapper
+ *	for the gifsave library.
+ *	AYM 1997-08-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"
+#if defined Y_UNIX
+#elif defined Y_DOS
+#include <gifsave.h>
+#endif
+
+
+#ifdef Y_DOS
+static int ShotGetPixel (int x, int y);
+#endif
+
+
+void ScreenShot (void)
+#if defined Y_UNIX
+{
+  return;  // FIXME
+}
+#elif defined Y_DOS
+{
+  int n;
+  int r;
+  int ShotWidth, ShotHeight;
+
+  ShotWidth = ScrMaxX+1;
+  ShotHeight = ScrMaxY+1-17-12;
+
+  LogMessage ("Writing screen shot to file yadex.gif\n");
+  r = GIF_Create ("yadex.gif", ShotWidth, ShotHeight, 16, 3);
+  if (r != GIF_OK)
+    LogMessage ("GIF_Create error %d\n", r);
+  GIF_SetColor ( 0, 0, 0, 0);  // BLACK
+  GIF_SetColor ( 1, 0, 0, 4);  // BLUE
+  GIF_SetColor ( 2, 0, 4, 0);  // GREEN
+  GIF_SetColor ( 3, 0, 4, 4);  // CYAN
+  GIF_SetColor ( 4, 4, 0, 0);  // RED
+  GIF_SetColor ( 5, 4, 0, 4);  // MAGENTA
+  GIF_SetColor ( 6, 4, 3, 0);  // BROWN
+  GIF_SetColor ( 7, 4, 4, 4);  // LIGHTGREY
+  GIF_SetColor ( 8, 2, 2, 2);  // DARKGREY
+  GIF_SetColor ( 9, 0, 0, 7);  // LIGHTBLUE
+  GIF_SetColor (10, 0, 7, 0);  // LIGHTGREEN
+  GIF_SetColor (11, 0, 7, 7);  // LIGHTCYAN
+  GIF_SetColor (12, 7, 0, 0);  // LIGHTRED
+  GIF_SetColor (13, 7, 0, 7);  // LIGHTMAGENTA
+  GIF_SetColor (14, 7, 7, 0);  // YELLOW
+  GIF_SetColor (15, 7, 7, 7);  // WHITE
+  r = GIF_CompressImage (0, 17, ShotWidth, ShotHeight, ShotGetPixel);
+  if (r != GIF_OK)
+    LogMessage ("GIF_CompressImage error %d\n", r);
+  r = GIF_Close ();
+  LogMessage ("GIF_Close returned %d\n", r);
+}
+
+
+static const char ColourCode[256] =
+{
+   0, 0, 0, 0,15, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,
+   0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,
+   0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,
+   0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,
+
+   0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,
+   0, 0, 0, 0, 0, 0, 0, 0,  7, 0, 0, 0, 0, 0, 0, 0,
+   8, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,
+  10, 0, 0, 0, 0, 0, 2, 0,  0, 0, 0, 0, 0, 0, 0, 0,
+
+   0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,
+   6, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,
+   0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,
+  12, 0, 0, 0, 0, 0, 0, 4,  0, 0, 0, 0, 0, 0, 3, 0,
+
+   0,11, 0, 0, 0, 9, 0, 0,  0, 0, 1, 0, 0, 0, 0, 0,
+   0, 0, 0, 0, 0, 0, 0,14,  0, 0, 0, 0, 0, 0, 0, 0,
+   0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,
+   0, 0, 0, 0, 0, 0, 0, 0,  0, 0,13, 0, 0, 5, 0, 0
+};
+
+static int ShotGetPixel (int x, int y)
+{
+  // FIXME: I assume we're in 256 colours
+  return ColourCode[getpixel (x, y)];
+}
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/selbox.cc	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,124 @@
+/*
+ *	selbox.cc
+ *	Selection box stuff.
+ *	AYM 1998-07-04
+ */
+
+
+/*
+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 "gfx.h"
+#include "selbox.h"
+
+
+static const int flags_1st_corner_set = 1;
+static const int flags_2nd_corner_set = 1 << 1;
+static const int flags_displayed      = 1 << 2;
+
+
+
+selbox_c::selbox_c (void)
+{
+  flags = 0;
+}
+
+
+void selbox_c::set_1st_corner (int x, int y)
+{
+  x1 = x;
+  y1 = y;
+  flags |= flags_1st_corner_set;
+}
+
+
+void selbox_c::set_2nd_corner (int x, int y)
+{
+  x2 = x;
+  y2 = y;
+  flags |= flags_2nd_corner_set;
+}
+
+
+void selbox_c::get_corners (int *x1, int *y1, int *x2, int *y2)
+{
+  if (x1 != NULL)
+    *x1 = this->x1;
+  if (y1 != NULL)
+    *y1 = this->y1;
+  if (x2 != NULL)
+    *x2 = this->x2;
+  if (y2 != NULL)
+    *y2 = this->y2;
+}
+
+
+void selbox_c::unset_corners (void)
+{
+  flags &= ~ (flags_1st_corner_set | flags_2nd_corner_set);
+}
+
+
+void selbox_c::draw (void)
+{
+  if ((flags & flags_1st_corner_set) && (flags & flags_2nd_corner_set))
+  {
+    set_colour (CYAN);
+    SetDrawingMode (1);
+    DrawMapLine (x1, y1, x1, y2);
+    DrawMapLine (x1, y2, x2, y2);
+    DrawMapLine (x2, y2, x2, y1);
+    DrawMapLine (x2, y1, x1, y1);
+    SetDrawingMode (0);
+    /* Those are needed by undraw() */
+    x1_disp = x1;
+    y1_disp = y1;
+    x2_disp = x2;
+    y2_disp = y2;
+    flags |= flags_displayed;
+  }
+}
+
+
+void selbox_c::undraw (void)
+{
+  if (flags & flags_displayed)
+  {
+    set_colour (CYAN);
+    SetDrawingMode (1);
+    DrawMapLine (x1_disp, y1_disp, x1_disp, y2_disp);
+    DrawMapLine (x1_disp, y2_disp, x2_disp, y2_disp);
+    DrawMapLine (x2_disp, y2_disp, x2_disp, y1_disp);
+    DrawMapLine (x2_disp, y1_disp, x1_disp, y1_disp);
+    SetDrawingMode (0);
+    flags &= ~ flags_displayed;
+  }
+}
+
+
+void selbox_c::clear (void)
+{
+  flags &= ~ flags_displayed;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/selbox.h	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,48 @@
+/*
+ *	selbox.h
+ *	Selection box stuff.
+ *	Header for selbox.c
+ *	AYM 1998-07-04
+ */
+
+
+#include "edwidget.h"
+
+
+class selbox_c : public edwidget_c
+{
+  public :
+
+    /* Methods used by edit_t */
+    selbox_c            ();
+    void set_1st_corner (int x, int y);
+    void set_2nd_corner (int x, int y);
+    void get_corners    (int *x1, int *y1, int *x2, int *y2);
+    void unset_corners  ();
+    /* Methods declared in edwidget_c */
+    void unset         ();
+    void draw          ();
+    void undraw        ();
+
+    int can_undraw ()
+      { return 1; }  // I have the ability to undraw myself
+
+    int need_to_clear ()
+      { return 0; }  // I know how to undraw myself.
+
+    void clear         ();
+
+  private :
+
+    int x1;		/* Coordinates of the first corner */
+    int y1;
+    int x2;		/* Coordinates of the second corner */
+    int y2;
+    int x1_disp;	/* x1 and y1 as they were last time draw() was called */
+    int y1_disp;
+    int x2_disp;	/* x2 and y2 as they were last time draw() was called */
+    int y2_disp;
+    int flags;
+};
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/selectn.cc	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,215 @@
+/*
+ *	selectn.cc
+ *	Selection stuff
+ *	AYM 1998-10-23
+ */
+
+
+/*
+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 "bitvec.h"
+#include "objid.h"
+#include "selectn.h"
+
+
+/*
+ *	IsSelected - test if an object is in a selection list
+ *
+ *	FIXME change the identifier
+ *	FIXME slow
+ */
+bool IsSelected (SelPtr list, int objnum)
+{
+  SelPtr cur;
+
+  for (cur = list; cur; cur = cur->next)
+    if (cur->objnum == objnum)
+      return true;
+  return false;
+}
+
+
+/*
+ *	DumpSelection -	list the contents of a selection
+ *
+ *	FIXME change the identifier
+ */
+void DumpSelection (SelPtr list)
+{
+  int n;
+  SelPtr cur;
+
+  printf ("Selection:");
+  for (n = 0, cur = list; cur; cur = cur->next, n++)
+    printf (" %d", cur->objnum);
+  printf ("  (%d)\n", n);
+}
+
+
+/*
+ *	SelectObject - add an object to a selection list
+ *
+ *	FIXME change the identifier
+ */
+void SelectObject (SelPtr *list, int objnum)
+{
+  SelPtr cur;
+
+  if (! is_obj (objnum))
+    fatal_error ("BUG: SelectObject called with %d", objnum);
+  cur = (SelPtr) GetMemory (sizeof (struct SelectionList));
+  cur->next = *list;
+  cur->objnum = objnum;
+  *list = cur;
+}
+
+
+/*
+ *	select_unselect_obj - add or remove an object from a selection list
+ *
+ *	If the object is not in the selection list, add it.  If
+ *	it already is, remove it.
+ */
+void select_unselect_obj (SelPtr *list, int objnum)
+{
+SelPtr cur;
+SelPtr prev;
+
+if (! is_obj (objnum))
+  fatal_error ("s/u_obj called with %d", objnum);
+for (prev = NULL, cur = *list; cur != NULL; prev = cur, cur = cur->next)
+  // Already selected: unselect it.
+  if (cur->objnum == objnum)
+  {
+    if (prev != NULL)
+      prev->next = cur->next;
+    else
+      *list = cur->next;
+    FreeMemory (cur);
+    if (prev != NULL)
+      cur = prev->next;
+    else
+      cur = (SelPtr) NULL;
+    return;
+  }
+
+  // Not selected: select it.
+  cur = (SelPtr) GetMemory (sizeof (struct SelectionList));
+  cur->next = *list;
+  cur->objnum = objnum;
+  *list = cur;
+}
+
+
+/*
+ *	UnSelectObject - remove an object from a selection list
+ *
+ *	FIXME change the identifier
+ */
+void UnSelectObject (SelPtr *list, int objnum)
+{
+  SelPtr cur, prev;
+
+  if (! is_obj (objnum))
+    fatal_error ("BUG: UnSelectObject called with %d", objnum);
+  prev = 0;
+  cur = *list;
+  while (cur)
+  {
+    if (cur->objnum == objnum)
+    {
+      if (prev)
+	prev->next = cur->next;
+      else
+	*list = cur->next;
+      FreeMemory (cur);
+      if (prev)
+	cur = prev->next;
+      else
+	cur = 0;
+    }
+    else
+    {
+      prev = cur;
+      cur = cur->next;
+    }
+  }
+}
+
+
+/*
+ *	ForgetSelection - clear a selection list
+ *
+ *	FIXME change the identifier
+ */
+void ForgetSelection (SelPtr *list)
+{
+  SelPtr cur, prev;
+
+  cur = *list;
+  while (cur)
+  {
+    prev = cur;
+    cur = cur->next;
+    FreeMemory (prev);
+  }
+  *list = 0;
+}
+
+
+/*
+ *	list_to_bitvec - make a bit vector from a list
+ *
+ *	The bit vector has <bitvec_size> elements. It's up to
+ *	the caller to delete the new bit vector after use.
+ */
+bitvec_c *list_to_bitvec (SelPtr list, size_t bitvec_size)
+{
+  SelPtr cur;
+  bitvec_c *bitvec;
+
+  bitvec = new bitvec_c (bitvec_size);
+  for (cur = list; cur; cur = cur->next)
+    bitvec->set (cur->objnum);
+  return bitvec;
+}
+
+
+/*
+ *	bitvec_to_list - make a list from a bitvec object
+ *
+ *	The items are inserted in the list from first to last
+ *	(i.e. item N in the bitvec is inserted before item N+1).
+ *	It's up to the caller to delete the new list after use.
+ */
+SelPtr bitvec_to_list (const bitvec_c &b)
+{
+  SelPtr list = 0;
+  for (size_t n = 0; n < b.nelements (); n++)
+    if (b.get (n))
+      SelectObject (&list, n);
+  return list;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/selectn.h	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,33 @@
+/*
+ *	selectn.h
+ *	Selection stuff
+ *	AYM 1998-10-23
+ */
+
+
+#ifndef YH_SELECTN  /* DO NOT INSERT ANYTHING BEFORE THIS LINE */
+#define YH_SELECTN
+
+
+class bitvec_c;
+
+
+// The selection list is used when more than one object is selected.
+typedef struct SelectionList *SelPtr;
+struct SelectionList
+{
+  SelPtr next;				// Next in list
+  int objnum;				// Object number
+};
+
+bool IsSelected (SelPtr, int);
+void DumpSelection (SelPtr list);
+void SelectObject (SelPtr *, int);
+void select_unselect_obj (SelPtr *list, int objnum);
+void UnSelectObject (SelPtr *, int);
+void ForgetSelection (SelPtr *);
+bitvec_c *list_to_bitvec (SelPtr list, size_t bitvec_size);
+SelPtr bitvec_to_list (const bitvec_c &b);
+
+
+#endif  /* DO NOT ADD ANYTHING AFTER THIS LINE */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/selpath.cc	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,227 @@
+/*
+ *	selpath.cc
+ *	Select all linedefs that form a path.
+ *	AYM 1999-03-24
+ */
+
+
+/*
+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 "bitvec.h"
+#include "levels.h"
+#include "objid.h"
+#include "selectn.h"
+#include "wstructs.h"
+
+
+static void select_linedefs_in_half_path (bitvec_c &sel,
+    bitvec_c &ldseen,
+    int linedef_no,
+    int vertex_no,
+    sel_op_t mode);
+static void select_1s_linedefs_in_half_path (bitvec_c &sel,
+    bitvec_c &ldseen,
+    int linedef_no,
+    int vertex_no,
+    sel_op_t mode);
+
+
+/*
+ *	select_linedefs_path
+ *	Add to selection <list> all linedefs in the same path as
+ *	linedef <linedef_no>, stopping at forks. If <mode> is not
+ *	YS_ADD but YS_REMOVE, those linedefs are removed from
+ *	the selection. If <mode> is YS_TOGGLE, each linedef is
+ *	removed if it was already in the selection, otherwise
+ *	added.
+ */
+void select_linedefs_path (SelPtr *list, int linedef_no, sel_op_t mode)
+{
+bitvec_c *ldsel = list_to_bitvec (*list, NumLineDefs);
+bitvec_c ldseen (NumLineDefs);  // Linedef already seen ?
+
+if (! is_obj (linedef_no))  // Sanity check
+   fatal_error ("select_linedef_path called with bad linedef_no=%d",
+      linedef_no);
+
+LDPtr ld = LineDefs + linedef_no;
+ldsel->frob (linedef_no, (bitvec_op_t) mode);
+ldseen.set (linedef_no);
+select_linedefs_in_half_path (*ldsel, ldseen, linedef_no, ld->start, mode);
+select_linedefs_in_half_path (*ldsel, ldseen, linedef_no, ld->end, mode);
+ForgetSelection (list);
+*list = bitvec_to_list (*ldsel);
+delete ldsel;
+}
+
+
+/*
+ *	select_linedefs_in_half_path
+ *	The routine looks for all linedefs other than linedef_no
+ *	that use vertex vertex_no. If there are none or more
+ *	than one, the search stop there and the function returns
+ *	without doing nothing. If there is exactly one, it is
+ *	added to the list sel and the function recursively calls
+ *	itself on the other vertex of that linedef.
+ */
+static void select_linedefs_in_half_path (bitvec_c &ldsel,
+    bitvec_c &ldseen,
+    int linedef_no,
+    int vertex_no,
+    sel_op_t mode)
+{
+  int next_linedef_no = OBJ_NO_NONE;
+  int next_vertex_no = OBJ_NO_NONE;
+
+  // Look for the next linedef in the path. It's the
+  // linedef that uses vertex vertex_no and is not
+  // linedef_no.
+  for (int n = 0; n < NumLineDefs; n++)
+  {
+    if (n == linedef_no)
+      continue;
+    if (LineDefs[n].start == vertex_no)
+    {
+      if (is_obj (next_linedef_no))
+	return;  // There is a fork in the path. Stop here.
+      // Continue search at the other end of the linedef
+      next_vertex_no = LineDefs[n].end;
+      next_linedef_no = n;
+    }
+    if (LineDefs[n].end == vertex_no)
+    {
+      if (is_obj (next_linedef_no))
+	return;  // There is a fork in the path. Stop here.
+      // Continue search at the other end of the linedef
+      next_vertex_no = LineDefs[n].start;
+      next_linedef_no = n;
+    }
+  }
+  if (! is_obj (next_linedef_no))  // None ? Reached end of path.
+    return;
+
+  // Already seen the next linedef ? The path must be
+  // closed. No need to do like the Dupondt.
+  if (ldseen.get (next_linedef_no))
+    return;
+
+  ldsel.frob (next_linedef_no, (bitvec_op_t) mode);
+  ldseen.set (next_linedef_no);
+  select_linedefs_in_half_path (ldsel, ldseen, next_linedef_no, next_vertex_no,
+      mode);
+}
+
+
+/*
+ *	select_1s_linedefs_path
+ *
+ *	Add to selection <list> all linedefs in the same path as
+ *	linedef <linedef_no>, stopping at forks. If <mode> is not
+ *	YS_ADD but YS_REMOVE, those linedefs are removed from
+ *	the selection. If <mode> is YS_TOGGLE, each linedef is
+ *	removed if it was already in the selection, otherwise
+ *	added.
+ */
+void select_1s_linedefs_path (SelPtr *list, int linedef_no, sel_op_t mode)
+{
+bitvec_c *ldsel = list_to_bitvec (*list, NumLineDefs);
+bitvec_c ldseen (NumLineDefs);  // Linedef already seen ?
+
+if (! is_obj (linedef_no))  // Sanity check
+   fatal_error ("select_linedef_path called with bad linedef_no=%d",
+      linedef_no);
+
+LDPtr ld = LineDefs + linedef_no;
+if (! is_obj (ld->sidedef1)  // The first linedef is not single-sided. Quit.
+    || is_obj (ld->sidedef2))
+  goto byebye;
+ldsel->frob (linedef_no, (bitvec_op_t) mode);
+ldseen.set (linedef_no);
+select_1s_linedefs_in_half_path (*ldsel, ldseen, linedef_no, ld->start, mode);
+select_1s_linedefs_in_half_path (*ldsel, ldseen, linedef_no, ld->end, mode);
+ForgetSelection (list);
+*list = bitvec_to_list (*ldsel);
+byebye:
+delete ldsel;
+}
+
+
+/*
+ *	select_1s_linedefs_in_half_path
+ *	Like select_linedefs_in_half_path() except that only
+ *	single-sided linedefs are selected.
+ */
+static void select_1s_linedefs_in_half_path (bitvec_c &ldsel,
+    bitvec_c &ldseen,
+    int linedef_no,
+    int vertex_no,
+    sel_op_t mode)
+{
+  int next_linedef_no = OBJ_NO_NONE;
+  int next_vertex_no = OBJ_NO_NONE;
+
+  // Look for the next linedef in the path. It's the
+  // linedef that uses vertex vertex_no and is not
+  // linedef_no.
+  for (int n = 0; n < NumLineDefs; n++)
+  {
+    if (n == linedef_no)
+      continue;
+    if (LineDefs[n].start == vertex_no
+	&& is_obj (LineDefs[n].sidedef1)
+	&& ! is_obj (LineDefs[n].sidedef2))
+    {
+      if (is_obj (next_linedef_no))
+	return;  // There is a fork in the path. Stop here.
+      // Continue search at the other end of the linedef
+      next_vertex_no = LineDefs[n].end;
+      next_linedef_no = n;
+    }
+    if (LineDefs[n].end == vertex_no
+	&& is_obj (LineDefs[n].sidedef1)
+	&& ! is_obj (LineDefs[n].sidedef2))
+    {
+      if (is_obj (next_linedef_no))
+	return;  // There is a fork in the path. Stop here.
+      // Continue search at the other end of the linedef
+      next_vertex_no = LineDefs[n].start;
+      next_linedef_no = n;
+    }
+  }
+  if (! is_obj (next_linedef_no))  // None ? Reached end of path.
+    return;
+
+  // Already seen the next linedef ? The path must be
+  // closed. No need to do like the Dupondt.
+  if (ldseen.get (next_linedef_no))
+    return;
+
+  ldsel.frob (next_linedef_no, (bitvec_op_t) mode);
+  ldseen.set (next_linedef_no);
+  select_1s_linedefs_in_half_path (ldsel, ldseen, next_linedef_no,
+      next_vertex_no, mode);
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/selpath.h	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,11 @@
+/*
+ *	selpath.h
+ *	Select linedefs in path.
+ *	AYM 1999-03-24
+ */
+
+
+void select_linedefs_path (SelPtr *list, int linedef_no, sel_op_t mode);
+void select_1s_linedefs_path (SelPtr *list, int linedef_no, sel_op_t mode);
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/selrect.cc	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,150 @@
+/*
+ *	selrect.cc
+ *	AYM 1999-03-24
+ */
+
+
+/*
+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 "levels.h"
+#include "objid.h"
+#include "selectn.h"
+#include "wstructs.h"
+
+
+/*
+   select all objects inside a given box
+*/
+
+void SelectObjectsInBox (SelPtr *list, int objtype, int x0, int y0, int x1, int y1) /* SWAP! */
+{
+int n, m;
+
+if (x1 < x0)
+   {
+   n = x0;
+   x0 = x1;
+   x1 = n;
+   }
+if (y1 < y0)
+   {
+   n = y0;
+   y0 = y1;
+   y1 = n;
+   }
+
+switch (objtype)
+   {
+   case OBJ_THINGS:
+      ObjectsNeeded (OBJ_THINGS, 0);
+      for (n = 0; n < NumThings; n++)
+	 if (Things[n].xpos >= x0 && Things[n].xpos <= x1
+	  && Things[n].ypos >= y0 && Things[n].ypos <= y1)
+            select_unselect_obj (list, n);
+      break;
+   case OBJ_VERTICES:
+      ObjectsNeeded (OBJ_VERTICES, 0);
+      for (n = 0; n < NumVertices; n++)
+	 if (Vertices[n].x >= x0 && Vertices[n].x <= x1
+	  && Vertices[n].y >= y0 && Vertices[n].y <= y1)
+            select_unselect_obj (list, n);
+      break;
+   case OBJ_LINEDEFS:
+      ObjectsNeeded (OBJ_LINEDEFS, OBJ_VERTICES, 0);
+      for (n = 0; n < NumLineDefs; n++)
+	 {
+	 /* the two ends of the line must be in the box */
+	 m = LineDefs[n].start;
+	 if (Vertices[m].x < x0 || Vertices[m].x > x1
+	  || Vertices[m].y < y0 || Vertices[m].y > y1)
+	    continue;
+	 m = LineDefs[n].end;
+	 if (Vertices[m].x < x0 || Vertices[m].x > x1
+	  || Vertices[m].y < y0 || Vertices[m].y > y1)
+	    continue;
+         select_unselect_obj (list, n);
+	 }
+      break;
+   case OBJ_SECTORS:
+      {
+      signed char *sector_status;
+      LDPtr ld;
+
+      sector_status = (signed char *) GetMemory (NumSectors);
+      memset (sector_status, 0, NumSectors);
+      for (n = 0, ld = LineDefs; n < NumLineDefs; n++, ld++)
+         {
+         VPtr v1, v2;
+         int s1, s2;
+
+         v1 = Vertices + ld->start;
+         v2 = Vertices + ld->end;
+
+         // Get the numbers of the sectors on both sides of the linedef
+	 if (is_sidedef (ld->sidedef1)
+	  && is_sector (SideDefs[ld->sidedef1].sector))
+	    s1 = SideDefs[ld->sidedef1].sector;
+	 else
+	    s1 = OBJ_NO_NONE;
+	 if (is_sidedef (ld->sidedef2)
+	  && is_sector (SideDefs[ld->sidedef2].sector))
+	    s2 = SideDefs[ld->sidedef2].sector;
+	 else
+	    s2 = OBJ_NO_NONE;
+
+         // The linedef is entirely within bounds.
+         // The sectors it touches _might_ be within bounds too.
+         if (v1->x >= x0 && v1->x <= x1
+          && v1->y >= y0 && v1->y <= y1
+          && v2->x >= x0 && v2->x <= x1
+          && v2->y >= y0 && v2->y <= y1)
+            {
+            if (is_sector (s1) && sector_status[s1] >= 0)
+               sector_status[s1] = 1;
+            if (is_sector (s2) && sector_status[s2] >= 0)
+               sector_status[s2] = 1;
+            }
+
+         // It's not. The sectors it touches _can't_ be within bounds.
+         else
+            {
+            if (is_sector (s1))
+               sector_status[s1] = -1;
+            if (is_sector (s2))
+               sector_status[s2] = -1;
+            }
+         }
+
+      // Now select all the sectors we found to be within bounds
+      ForgetSelection (list);
+      for (n = 0; n < NumSectors; n++)
+         if (sector_status[n] > 0)
+            SelectObject (list, n);
+      FreeMemory (sector_status);
+      }
+      break;
+   }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/serialnum.cc	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,79 @@
+/*
+ *	serialnum.cc
+ *	Serial_num class
+ *	AYM 2000-04-06
+ */
+
+
+/*
+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 "serialnum.h"
+
+
+Serial_num::Serial_num ()
+{
+  serial_no      = 0;
+  serial_is_used = false;
+}
+
+
+/*
+ *	stale - call this to check whether a serial number has become stale
+ */
+bool Serial_num::outdated (const serial_num_t& token)
+{
+  return token != serial_no;
+}
+
+
+/*
+ *	update - get the revision number
+ */
+void Serial_num::update (serial_num_t& token)
+{
+  serial_is_used = true;
+  token          = serial_no;
+}
+
+
+/*
+ *	bump - call this to increment the revision number
+ */
+void Serial_num::bump ()
+{
+  /* If no one uses the current serial number, bumping it would
+     be a waste of S/N space. */
+  if (! serial_is_used)
+    return;
+
+  serial_no++;
+  serial_is_used = false;
+  if (serial_no == 0)  // Extremely unlikely to ever happen
+  {
+    nf_bug ("Serial_num(%p)::serial_no wrapped around", this);
+  }
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/serialnum.h	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,51 @@
+/*
+ *	serialnum.h
+ *	Serial_num class
+ *	AYM 2000-04-06
+ */
+
+
+/*
+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.
+*/
+
+
+#ifndef YH_SERIALNUM  /* DO NOT INSERT ANYTHING BEFORE THIS LINE */
+#define YH_SERIALNUM
+
+
+typedef unsigned long serial_num_t;
+
+
+class Serial_num
+{
+  public :
+    Serial_num ();
+    void         update (serial_num_t& token);
+    bool         outdated (const serial_num_t& token);
+    void         bump ();
+  private :
+    serial_num_t serial_no;
+    bool         serial_is_used;
+};
+
+
+#endif  /* DO NOT ADD ANYTHING AFTER THIS LINE */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/spot.h	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,89 @@
+/*
+ *	spot.h
+ *	AYM 1998-12-14
+ */
+
+
+/*
+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 "edwidget.h"
+#include "gfx.h"
+
+
+class spot_c : public edwidget_c
+{
+  public :
+
+    /*
+     *	Specific to this class
+     */
+    spot_c () { visible = 0; visible_disp = 0; }
+    void set (int x, int y) { this->x = x; this->y = y; visible = 1; }
+
+    /*
+     *	Inherited from edwidget_c
+     */
+    void unset () { visible = 0; }
+
+    void draw ()
+    {
+      if (visible && (! visible_disp || x_disp != x || y_disp != y))
+      {
+	SetDrawingMode (1);
+	push_colour (LIGHTGREEN);
+	draw_map_point (x, y);
+	pop_colour ();
+	SetDrawingMode (0);
+	visible_disp = 1;
+	x_disp = x;
+	y_disp = y;
+      }
+    }
+
+    void undraw ()
+    {
+      if (visible_disp)
+      {
+	SetDrawingMode (1);
+	push_colour (LIGHTGREEN);
+	draw_map_point (x_disp, y_disp);
+	pop_colour ();
+	SetDrawingMode (0);
+	visible_disp = 0;
+      }
+    }
+
+    int can_undraw () { return 1; }
+    int need_to_clear () { return 0; }
+    void clear () { visible_disp = 0; }
+
+  private :
+    int visible;
+    int visible_disp;
+    int x;
+    int y;
+    int x_disp;
+    int y_disp;
+};
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/spritdir.cc	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,66 @@
+/*
+ *	spritdir.cc - Sprite_dir class
+ *	AYM 2000-06-01
+ */
+
+
+/*
+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 <functional>
+#include "dependcy.h"
+#include "lumpdir.h"
+#include "spritdir.h"
+#include "wadname.h"
+#include "wadnamec.h"
+
+
+/*
+ *	Sprite_dir::loc_by_root - find sprite by prefix
+ *	
+ *      Return the (wad, offset, length) location of the first
+ *      lump by alphabetical order whose name begins with
+ *      <name>. If not found, set loc.wad to 0.
+ */
+void Sprite_dir::loc_by_root (const char *name, Lump_loc& loc)
+{
+  if (dependency->outdated ())
+    refresh ();
+
+  /* Caller asked for same lump twice in a row. Save us a second
+     search. */
+  if (have_prev && ! y_strnicmp (name, name_prev, WAD_NAME))
+  {
+    loc = loc_prev;
+    return;
+  }
+
+  Lump_map::const_iterator i = lump_map.lower_bound (name);
+  have_prev = true;
+  if (i == lump_map.end () || y_strnicmp (name, i->first.name, strlen (name)))
+    loc.wad = loc_prev.wad = 0;
+  else
+    loc = loc_prev = i->second;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/spritdir.h	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,55 @@
+/*
+ *	spritdir.h
+ *	Sprite_dir class
+ *	AYM 2000-05-31
+ */
+
+
+/*
+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.
+*/
+
+
+#ifndef YH_SPRITDIR  /* DO NOT INSERT ANYTHING BEFORE THIS LINE */
+#define YH_SPRITDIR
+
+
+#include "lumpdir.h"
+
+
+/*
+ *	Sprite_dir
+ *
+ *	This is a specialization of Lump_dir that has an
+ *	additional method : loc_by_root() which retrieves the
+ *	first entry whose name begins with the argument.
+ */
+
+
+class Sprite_dir : public Lump_dir
+{
+  public :
+    Sprite_dir (MDirPtr *md, Serial_num *sn) : Lump_dir (md, 'S', sn) { }
+    void loc_by_root (const char *name, Lump_loc& loc);
+};
+
+
+#endif  /* DO NOT ADD ANYTHING AFTER THIS LINE */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/sticker.cc	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,613 @@
+/*
+ *	sticker.cc - Sticker class
+ *	AYM 2000-07-06
+ */
+
+
+/*
+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"
+#if defined Y_X11
+#  include <X11/Xlib.h>
+#  include <X11/Xutil.h>  // XDestroyImage
+#elif defined Y_BGI
+#  include <graphics.h>
+#endif
+#include "gcolour2.h"
+#include "gcolour3.h"
+#include "gfx.h"
+#include "img.h"
+#include "sticker.h"
+
+
+class Sticker_priv
+{
+  public :
+    Sticker_priv ();
+    ~Sticker_priv ();
+    void clear ();
+    void load (const Img &img, bool opaque);
+    XImage *make_ximage (const Img& img);
+    XImage *make_bitmap (const Img& img);
+    bool opaque;
+    bool has_data;
+    int  width;
+    int  height;
+#if defined Y_X11
+    XImage *ximage;	// Used only if opaque
+    Pixmap pixmap;	// Used only if not opaque
+    Pixmap mask;	// Used only if not opaque
+#elif defined Y_BGI
+    void *putimage_data;// Used only if opaque
+    img_pixel_t *pixels	// Used only if not opaque
+#endif
+};
+
+
+/*
+ *	Sticker::Sticker - create an empty Sticker
+ */
+Sticker::Sticker ()
+{
+  priv = new Sticker_priv ();
+}
+
+
+/*
+ *	Sticker::Sticker - create a Sticker from an Img
+ */
+Sticker::Sticker (const Img& img, bool opaque)
+{
+  priv = new Sticker_priv ();
+  priv->load (img, opaque);
+}
+
+
+/*
+ *	Sticker::~Sticker - destroy a Sticker
+ */
+Sticker::~Sticker ()
+{
+  delete priv;
+} 
+
+
+/*
+ *	Sticker::is_clear - tells whether a sprite is "empty"
+ */
+bool Sticker::is_clear ()
+{
+  return ! priv->has_data;
+}
+
+
+/*
+ *	Sticker::clear - clear a Sticker
+ */
+void Sticker::clear ()
+{
+  priv->clear ();
+}
+
+
+/*
+ *	Sticker::load - load an Img into a Sticker
+ */
+void Sticker::load (const Img& img, bool opaque)
+{
+  priv->load (img, opaque);
+}
+
+
+/*
+ *	Sticker::draw - draw a Sticker
+ */
+void Sticker::draw (Drawable drw, char grav, int x, int y)
+{
+  if (! priv->has_data)
+    return;
+  int x0 = grav == 'c' ? x - priv->width  / 2 : x;
+  int y0 = grav == 'c' ? y - priv->height / 2 : y;
+#if defined Y_X11
+  if (priv->opaque)
+  {
+    XPutImage (dpy, drw, gc, priv->ximage, 0, 0,
+      x0, y0, priv->width, priv->height);
+  }
+  else
+  {
+    XSetClipMask (dpy, gc, priv->mask);
+    XSetClipOrigin (dpy, gc, x0, y0);
+    XCopyArea (dpy, priv->pixmap, drw, gc, 0, 0, priv->width,
+      priv->height, x0, y0);
+    XSetClipMask (dpy, gc, None);
+  }
+#elif defined Y_BGI
+  // THE BGI CODE IS UNTESTED !! -- AYM 2000-08-13
+  if (priv->opaque)
+  {
+    putimage (x0, y0, priv->putimage_data, COPY_PUT);
+  }
+  else
+  {
+    char img_pixel_t *data = priv->pixels;
+    int _xmax = x0 + priv->width;
+    int _ymax = y0 + priv->height;
+    for (; x0 < _ymax; x0++)
+      for (; y0 < _xmax; y0++)
+      {
+	if (*data != IMG_TRANSP)
+	  putpixel (x0, y0, *data);
+	data++;
+      }
+  }
+#endif
+}
+
+
+Sticker_priv::Sticker_priv ()
+{
+  has_data = false;
+}
+
+
+Sticker_priv::~Sticker_priv ()
+{
+  clear ();
+}
+
+
+void Sticker_priv::clear ()
+{
+  if (has_data)
+  {
+#if defined Y_X11
+    if (opaque)
+    {
+      XDestroyImage (ximage);  // Also frees buf.
+    }
+    else
+    {
+      XFreePixmap (dpy, pixmap);
+      XFreePixmap (dpy, mask);
+    }
+    has_data = false;
+#elif defined Y_BGI
+    if (opaque)
+    {
+      FreeMemory (priv->putimage_data);
+    }
+    else
+    {
+      FreeMemory (priv->pixels);
+    }
+#endif
+  }
+}
+
+ 
+void Sticker_priv::load (const Img& img, bool opaque)
+{
+  this->opaque = opaque;
+  clear ();
+
+  width  = img.width ();
+  height = img.height ();
+  if (width < 1 || height < 1)
+    return;  // Can't create Pixmaps with null dimensions...
+
+#if defined Y_X11
+  if (opaque)
+  {
+    ximage = make_ximage (img);
+    if (ximage != 0)
+      has_data = true;
+  }
+  else
+  {
+    // Create a pixmap and copy the image onto it.
+    pixmap = XCreatePixmap (dpy, win, width, height, win_depth);
+    XImage *image = make_ximage (img);
+    if (image != 0)
+    {
+      XPutImage (dpy, pixmap, gc, image, 0, 0, 0, 0, width, height);
+      XDestroyImage (image);
+    }
+
+    // Create the mask pixmap and copy the silhouette onto it.
+    mask = XCreatePixmap (dpy, win, width, height, 1);
+    XImage *mask_image = make_bitmap (img);
+    if (mask_image != 0)
+    {
+      GC mask_gc = XCreateGC (dpy, mask, 0, 0);
+      XSetBackground (dpy, mask_gc, 0);
+      XSetForeground (dpy, mask_gc, 1);
+      XPutImage (dpy, mask, mask_gc, mask_image, 0, 0, 0, 0, width, height);
+      XFreeGC (dpy, mask_gc);
+      XDestroyImage (mask_image);
+    }
+
+    has_data = true;
+  }
+#elif defined Y_BGI
+  // THE BGI CODE IS UNTESTED !! -- AYM 2000-08-13
+  if (opaque)
+  {
+    putimage_data = GetMemory (4 + width * height * sizeof (img_pixel_t));
+    if (putimage_data == 0)
+    {
+      warn ("Out of memory in Sticker::load()\n");
+      return;
+    }
+    if (GfxMode < -1)  // The VESA drivers needs (size - 1) instead of (size)
+    {
+      ((unsigned short *) putimage_data)[0] = width  - 1;
+      ((unsigned short *) putimage_data)[1] = height - 1;
+    }
+    else
+    {
+      ((unsigned short *) putimage_data)[0] = width;
+      ((unsigned short *) putimage_data)[1] = height;
+    }
+    memcpy (((img_pixel_t *) putimage_data) + 4, img.buf (),
+      width * height * sizeof (img_pixel_t));
+    has_data = true;
+  }
+  else
+  {
+    pixels = (img_pixel_t *) GetMemory (width * height * sizeof (img_pixel_t));
+    if (pixels == 0)
+    {
+      warn ("Out of memory in Sticker::load()\n");
+      return;
+    }
+    memcpy (pixels, img.buf (), width * height * sizeof (img_pixel_t));
+    has_data = true;
+  }
+#endif
+}
+
+
+#if defined Y_X11
+/*
+ *	Sticker_priv:ximage - create XImage from Img
+ *
+ *	Return pointer to XImage on success, null pointer on
+ *	failure.
+ */
+XImage *Sticker_priv::make_ximage (const Img& img)
+{
+  // How many bytes per line do we need ?
+  size_t bytes_per_line = width * ximage_bpp;
+  if (ximage_quantum == 0)  // Paranoia
+  {
+    nf_bug ("ximage_quantum == 0");
+    ximage_quantum = 1;
+  }
+  size_t padding = 0;
+  while (bytes_per_line % ximage_quantum)
+  {
+    bytes_per_line++;
+    padding++;
+  }
+  u8 *buf = (u8 *) GetMemory ((unsigned long) bytes_per_line * height);
+  if (! buf)
+  {
+    err ("Not enough memory to display %dx%d image", width, height);
+    return 0;
+  }
+
+  // Copy the Img onto the XImage.
+  const img_pixel_t *image_end = img.buf () + width * height;
+  if (ximage_bpp == 1)
+  {
+    register const img_pixel_t *image_ptr;
+    register u8 *buf_ptr = (u8 *) buf;
+    if (padding == 0)
+    {
+      for (image_ptr = img.buf (); image_ptr < image_end; image_ptr++)
+	*buf_ptr++ = (u8) game_colour[*image_ptr];
+    }
+    else
+    {
+      const img_pixel_t *image_line_end;
+      int img_width = width;
+      for (image_ptr = image_line_end = img.buf (); image_ptr < image_end;)
+      {
+	image_line_end += img_width;
+	for (; image_ptr < image_line_end; image_ptr++)
+	  *buf_ptr++ = (u8) game_colour[*image_ptr];
+	buf_ptr += padding;  // Line padding
+      }
+    }
+  }
+
+  else if (ximage_bpp == 2)
+  {
+    register const img_pixel_t *image_ptr;
+    register u16 *buf_ptr = (u16 *) buf;
+    if (cpu_big_endian == x_server_big_endian)
+    {
+      if (padding == 0)
+      {
+	for (image_ptr = img.buf (); image_ptr < image_end; image_ptr++)
+	  *buf_ptr++ = (u16) game_colour[*image_ptr];
+      }
+      else
+      {
+	const img_pixel_t *image_line_end;
+	int img_width = width;
+	for (image_ptr = image_line_end = img.buf (); image_ptr < image_end;)
+	{
+	  image_line_end += img_width;
+	  for (; image_ptr < image_line_end; image_ptr++)
+	    *buf_ptr++ = (u16) game_colour[*image_ptr];
+	  buf_ptr = (u16 *) ((char *) buf_ptr + padding);  // Line padding
+	}
+      }
+    }
+    else  // Different endiannesses so swap bytes
+    {
+      if (padding == 0)
+      {
+	for (image_ptr = img.buf (); image_ptr < image_end; image_ptr++)
+	   *buf_ptr++ = (u16) (
+		 (game_colour[*image_ptr] >> 8)  // Assume game_colour unsigned
+	       | (game_colour[*image_ptr] << 8));
+      }
+      else
+      {
+	const img_pixel_t *image_line_end;
+	int img_width = width;
+	for (image_ptr = image_line_end = img.buf (); image_ptr < image_end;)
+	{
+	  image_line_end += img_width;
+	  for (; image_ptr < image_line_end; image_ptr++)
+	     *buf_ptr++ = (u16) (
+		   (game_colour[*image_ptr] >> 8)  // Assume game_colour uns.
+		 | (game_colour[*image_ptr] << 8));
+	  buf_ptr = (u16 *) ((char *) buf_ptr + padding);  // Line padding
+	}
+      }
+    }
+  }
+
+  else if (ximage_bpp == 3)
+  {
+    const pv24_t *const pixel_value = game_colour_24.lut ();
+    register const img_pixel_t *image_ptr;
+    register pv24_t *buf_ptr = (pv24_t *) buf;
+    if (padding == 0)
+    {
+      for (image_ptr = img.buf (); image_ptr < image_end; image_ptr++)
+	memcpy (buf_ptr++, pixel_value + *image_ptr, sizeof *buf_ptr);
+    }
+    else
+    {
+      const img_pixel_t *image_line_end;
+      int img_width = width;
+      for (image_ptr = image_line_end = img.buf (); image_ptr < image_end;)
+      {
+	image_line_end += img_width;
+	for (; image_ptr < image_line_end; image_ptr++)
+	  memcpy (buf_ptr++, pixel_value + *image_ptr, sizeof *buf_ptr);
+	buf_ptr = (pv24_t *) ((char *) buf_ptr + padding);  // Line padding
+      }
+    }
+  }
+
+  else if (ximage_bpp == 4)
+  {
+    register const img_pixel_t *image_ptr;
+    register u32 *buf_ptr = (u32 *) buf;
+    if (cpu_big_endian == x_server_big_endian)
+    {
+      if (padding == 0)
+      {
+	for (image_ptr = img.buf (); image_ptr < image_end; image_ptr++)
+	  *buf_ptr++ = (u32) game_colour[*image_ptr];
+      }
+      else
+      {
+	const img_pixel_t *image_line_end;
+	int img_width = width;
+	for (image_ptr = image_line_end = img.buf (); image_ptr < image_end;)
+	{
+	  image_line_end += img_width;
+	  for (; image_ptr < image_line_end; image_ptr++)
+	    *buf_ptr++ = (u32) game_colour[*image_ptr];
+	  buf_ptr = (u32 *) ((char *) buf_ptr + padding);  // Line padding
+	}
+      }
+    }
+    else  // Different endiannesses so swap bytes
+    {
+      if (padding == 0)
+      {
+	for (image_ptr = img.buf (); image_ptr < image_end; image_ptr++)
+	  *buf_ptr++ = (u32) (
+	      (game_colour[*image_ptr] >> 24)  // Assume game_colour unsigned
+	    | (game_colour[*image_ptr] >> 8) & 0x0000ff00
+	    | (game_colour[*image_ptr] << 8) & 0x00ff0000
+	    | (game_colour[*image_ptr] << 24));
+      }
+      else
+      {
+	const img_pixel_t *image_line_end;
+	int img_width = width;
+	for (image_ptr = image_line_end = img.buf (); image_ptr < image_end;)
+	{
+	  image_line_end += img_width;
+	  for (; image_ptr < image_line_end; image_ptr++)
+	    *buf_ptr++ = (u32) (
+		(game_colour[*image_ptr] >> 24)  // Assume game_colour uns.
+	      | (game_colour[*image_ptr] >> 8) & 0x0000ff00
+	      | (game_colour[*image_ptr] << 8) & 0x00ff0000
+	      | (game_colour[*image_ptr] << 24));
+	  buf_ptr = (u32 *) ((char *) buf_ptr + padding);  // Line padding
+	}
+      }
+    }
+  }
+
+  XImage *ximage = XCreateImage (dpy, win_vis, win_depth, ZPixmap, 0,
+    (char *) buf, width, height, 8, bytes_per_line);
+  if (ximage == 0)
+  {
+    err ("XCreateImage() returned NULL");
+    FreeMemory (buf);
+  }
+  else
+  {
+    if (ximage->byte_order == LSBFirst && ! x_server_big_endian
+     || ximage->byte_order == MSBFirst && x_server_big_endian)
+      ;  // OK
+    else
+      warn ("image byte_order %d doesn't match X server endianness\n",
+	  ximage->byte_order);
+  }
+  return ximage;
+}
+#endif  /* Y_X11 */
+
+
+#ifdef Y_X11
+/*
+ *	Sticker_priv::make_bitmap - create 1-bpp XImage from Img
+ *
+ *	Return pointer on XImage on success, null pointer on
+ *	failure.
+ */
+XImage *Sticker_priv::make_bitmap (const Img& img)
+{
+  int width  = img.width ();
+  int height = img.height ();
+
+  // How many bytes per line do we need ?
+  if (CHAR_BIT != 8)  // Pure paranoia
+  {
+    nf_bug ("Panic: CHAR_BIT != 8 (%d)", (int) CHAR_BIT);
+    return 0;
+  }
+  const size_t bitmap_pad     = BitmapPad (dpy);
+  const size_t bytes_per_line = (width + bitmap_pad - 1) / bitmap_pad
+				* bitmap_pad / CHAR_BIT;
+  u8 *buf = (u8 *) GetMemory ((unsigned long) bytes_per_line * height);
+  if (! buf)
+  {
+    err ("Not enough memory to display %dx%d image", width, height);
+    return 0;
+  }
+
+  // Copy the "profile" of the Img onto the XImage
+  {
+    int bitmap_bit_order = BitmapBitOrder (dpy);
+    register u8 *buf_ptr = (u8 *) buf;
+    const int IMG_TRANSP = 0;
+    const img_pixel_t       *image_ptr = img.buf ();
+    const img_pixel_t *const image_end = image_ptr + width * height;
+
+    while (image_ptr < image_end)
+    {
+      register const u8 *src   = image_ptr;
+      const u8 *const    stop1 = src + width - 7;
+      const u8 *const    stop2 = image_ptr + width;
+      u8* dest = buf_ptr;
+      if (bitmap_bit_order == LSBFirst)
+      {
+	while (src < stop1)
+	{
+	  register u8 d = 0;
+	  if (*src++ != IMG_TRANSP) d |= 1;
+	  if (*src++ != IMG_TRANSP) d |= 2;
+	  if (*src++ != IMG_TRANSP) d |= 4;
+	  if (*src++ != IMG_TRANSP) d |= 8;
+	  if (*src++ != IMG_TRANSP) d |= 16;
+	  if (*src++ != IMG_TRANSP) d |= 32;
+	  if (*src++ != IMG_TRANSP) d |= 64;
+	  if (*src++ != IMG_TRANSP) d |= 128;
+	  *dest++ = d;
+	}
+	if (src < stop2)
+	{
+	  register u8 d = 0;
+	  if (*src++ != IMG_TRANSP) d |= 1;   if (src >= stop2) goto eol_le;
+	  if (*src++ != IMG_TRANSP) d |= 2;   if (src >= stop2) goto eol_le;
+	  if (*src++ != IMG_TRANSP) d |= 4;   if (src >= stop2) goto eol_le;
+	  if (*src++ != IMG_TRANSP) d |= 8;   if (src >= stop2) goto eol_le;
+	  if (*src++ != IMG_TRANSP) d |= 16;  if (src >= stop2) goto eol_le;
+	  if (*src++ != IMG_TRANSP) d |= 32;  if (src >= stop2) goto eol_le;
+	  if (*src++ != IMG_TRANSP) d |= 64;  if (src >= stop2) goto eol_le;
+	  if (*src++ != IMG_TRANSP) d |= 128;
+	  eol_le:
+	  *dest = d;
+	}
+      }
+      else if (bitmap_bit_order == MSBFirst)
+      {
+	while (src < stop1)
+	{
+	  register u8 d = 0;
+	  if (*src++ != IMG_TRANSP) d |= 128;
+	  if (*src++ != IMG_TRANSP) d |= 64;
+	  if (*src++ != IMG_TRANSP) d |= 32;
+	  if (*src++ != IMG_TRANSP) d |= 16;
+	  if (*src++ != IMG_TRANSP) d |= 8;
+	  if (*src++ != IMG_TRANSP) d |= 4;
+	  if (*src++ != IMG_TRANSP) d |= 2;
+	  if (*src++ != IMG_TRANSP) d |= 1;
+	  *dest++ = d;
+	}
+	if (src < stop2)
+	{
+	  register u8 d = 0;
+	  if (*src++ != IMG_TRANSP) d |= 128; if (src >= stop2) goto eol_be;
+	  if (*src++ != IMG_TRANSP) d |= 64;  if (src >= stop2) goto eol_be;
+	  if (*src++ != IMG_TRANSP) d |= 32;  if (src >= stop2) goto eol_be;
+	  if (*src++ != IMG_TRANSP) d |= 16;  if (src >= stop2) goto eol_be;
+	  if (*src++ != IMG_TRANSP) d |= 8;   if (src >= stop2) goto eol_be;
+	  if (*src++ != IMG_TRANSP) d |= 4;   if (src >= stop2) goto eol_be;
+	  if (*src++ != IMG_TRANSP) d |= 2;   if (src >= stop2) goto eol_be;
+	  if (*src++ != IMG_TRANSP) d |= 1;
+	  eol_be:
+	  *dest = d;
+	}
+      }
+      buf_ptr += bytes_per_line;
+      image_ptr += width;
+    }
+  }
+
+  XImage *ximage = XCreateImage (dpy, win_vis, 1, XYBitmap, 0,
+    (char *) buf, width, height, bitmap_pad, bytes_per_line);
+  if (ximage == 0)
+  {
+    err ("XCreateImage() returned NULL");
+    FreeMemory (buf);
+    return 0;
+  }
+  return ximage;
+}
+#endif  /* Y_X11 */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/sticker.h	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,27 @@
+/*
+ *	sticker.h - Sticker class
+ *	AYM 2000-07-06
+ */
+
+
+class Img;
+class Sticker_priv;
+
+
+class Sticker
+{
+  public :
+    Sticker ();
+    Sticker (const Img& img, bool opaque);
+    ~Sticker ();
+    bool is_clear ();
+    void clear ();
+    void load (const Img& img, bool opaque);
+    void draw (Drawable drw, char grav, int x, int y);
+
+  private :
+    Sticker (const Sticker&);			// Too lazy to implement it
+    Sticker& operator= (const Sticker&);	// Too lazy to implement it
+    Sticker_priv *priv;
+};
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/swapmem.cc	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,345 @@
+/*
+   Memory swapping by Raphaël Quinet <quinet@montefiore.ulg.ac.be>
+   and Christian Johannes Schladetsch <s924706@yallara.cs.rmit.OZ.AU>
+
+   You are allowed to use any parts of this code in another program, as
+   long as you give credits to the authors in the documentation and in
+   the program itself.  Read the file README.1ST for more information.
+
+   This program comes with absolutely no warranty.
+
+   SWAPMEM.C - When the memory is low....
+
+   Note from RQ:
+      Yuck!  I don't like this horrible thing.  The program should be
+      able to swap almost anything to XMS or to disk, not only the
+      five objects used here (Things, LineDefs, SideDefs, Vertices and
+      Sectors).  That was a quick and dirty hack...  I didn't have the
+      time to write a cleaner code...
+
+   Note2 from RQ:
+      After having tested these routines, I see that they are not very
+      useful...  I'm still getting "out of memory" errors while editing
+      E2M7 and other huge levels.  I should rewrite all this for GCC,
+      use a flat memory model and a DOS extender, then just delete all
+      this code...  I will have to do that anyway if I want to port it
+      to other systems (Unix, Linux), so why not?
+      Moral of the story: never waste long hours writing high-level
+      memory swapping routines on a deficient OS.  Use a real OS with
+      a better memory management instead.
+
+   Note for CJS:
+      It should be easy to include your XMS code in this file.  Just
+      add the necessary lines in InitSwap(), SwapIn() and SwapOut().
+      You won't need to edit any other file.  Put all your routines
+      in XMS.C, with the necessary includes in XMS.H.  Please keep it
+      short and simple... :-)
+      ... And delete this note once you're done.
+*/
+
+
+/*
+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 "levels.h"
+#include "objid.h"
+#ifdef SWAP_TO_XMS
+#include "xms.h"
+typedef XMSHandle SwapHandle;	/* XMS handle */
+#define INVALID_HANDLE		-1
+#else
+typedef char SwapHandle[128];	/* name of the temporary disk file */
+#define INVALID_HANDLE		"..."
+#endif /* SWAP_TO_XMS */
+
+/* global variables */
+bool NeedThings = false;
+bool NeedLineDefs = false;
+bool NeedSideDefs = false;
+bool NeedVertices = false;
+bool NeedSectors = false;
+SwapHandle ThingsH;
+SwapHandle LineDefsH;
+SwapHandle SideDefsH;
+SwapHandle VerticesH;
+SwapHandle SectorsH;
+
+
+/*
+   do the necessary initialisation for the secondary storage
+*/
+
+void InitSwap ()
+{
+#ifdef SWAP_TO_XMS
+/* Init XMS */
+...
+#else
+strcpy (ThingsH, INVALID_HANDLE);
+strcpy (LineDefsH, INVALID_HANDLE);
+strcpy (SideDefsH, INVALID_HANDLE);
+strcpy (VerticesH, INVALID_HANDLE);
+strcpy (SectorsH, INVALID_HANDLE);
+#endif /* SWAP_TO_XMS */
+}
+
+
+
+/*
+   moves an object from secondary storage to lower RAM
+*/
+
+void huge *SwapIn (SwapHandle handle, unsigned long size)
+{
+void huge *ptr;
+#ifdef SWAP_TO_XMS
+/* allocate a new memory block (in lower RAM) */
+ptr = GetFarMemory (size);
+/* read the data from XMS */
+...
+/* free the XMS memory block */
+...
+/* delete the handle */
+...
+#else
+FILE      *file;
+char huge *data;
+SwapHandle oldhandle;
+
+/* Note from RQ:
+      the following test is there to prevent an infinite loop when
+      SwapIn calls GetFarMemory, which calls FreeSomeMemory, which
+      in turn calls SwapOut, then SwapIn...
+ */
+if (! strcmp (handle, INVALID_HANDLE))
+   return NULL;
+#ifdef DEBUG
+LogMessage ("swapping in %lu bytes from %s\n", size, handle);
+#endif /* DEBUG */
+strcpy (oldhandle, handle);
+/* invalidate the handle (must be before "GetFarMemory") */
+strcpy (handle, INVALID_HANDLE);
+/* allocate a new memory block (in lower RAM) */
+ptr = GetFarMemory (size);
+/* read the data from the temporary file */
+file = fopen (oldhandle, "rb");
+data = (char huge *) ptr;
+if (file == NULL)
+{
+#ifdef DEBUG
+   LogMessage ("\nFree memory before crash: %lu bytes.", farcoreleft ());
+#endif /* DEBUG */
+   fatal_error ("error opening temporary file \"%s\"", oldhandle);
+}
+while (size > 0x8000)
+{
+   if (fread (data, 1, 0x8000, file) != 0x8000)
+      fatal_error ("error reading from temporary file \"%s\"", oldhandle);
+   data = data + 0x8000;
+   size -= 0x8000;
+}
+if (fread (data, 1, size, file) != size)
+   fatal_error ("error reading from temporary file \"%s\"", oldhandle);
+fclose (file);
+/* delete the file */
+unlink (oldhandle);
+#endif /* !SWAP_TO_XMS */
+return ptr;
+}
+
+
+
+/*
+   moves an object from lower RAM to secondary storage
+*/
+
+void SwapOut (void huge *ptr, SwapHandle handle, unsigned long size)
+{
+#ifdef SWAP_TO_XMS
+/* get a new XMS handle */
+...
+/* write the data to XMS */
+...
+#else
+FILE      *file;
+char huge *data;
+
+// get a new (unique) file name
+const char *basename = "yadexswpXXXXXX";  // 14 characters
+const char *dir      = getenv ("TMPDIR");
+if (dir == 0 || strlen (dir) + 1 + strlen (basename) >= sizeof (SwapHandle))
+   dir = "/tmp";
+y_snprintf (handle, sizeof (SwapHandle), "%s/%s", dir, basename);
+if (mkstemp (handle) == -1)
+{
+#ifdef DEBUG
+   LogMessage ("\nFree memory before crash: %lu bytes.", farcoreleft ());
+#endif
+   fatal_error ("cannot create a temporary file from \"%s\" (%s)",
+      handle, strerror (errno));
+}
+#ifdef DEBUG
+LogMessage ("swapping out %lu bytes to %s\n", size, handle);
+#endif /* DEBUG */
+// write the data to the temporary file
+data = (char huge *) ptr;
+file = fopen (handle, "wb");
+if (file == NULL)
+{
+#ifdef DEBUG
+   LogMessage ("\nFree memory before crash: %lu bytes.", farcoreleft ());
+#endif /* DEBUG */
+   fatal_error ("error creating temporary file \"%s\" (%s)",
+      handle, strerror (errno));
+}
+while (size > 0x8000)
+{
+   if (fwrite (data, 1, 0x8000, file) != 0x8000)
+      fatal_error ("error writing to temporary file \"%s\"", handle);
+   data = data + 0x8000;
+   size -= 0x8000;
+}
+if (fwrite (data, 1, size, file) != size)
+   fatal_error ("error writing to temporary file \"%s\"", handle);
+if (fclose (file))
+   fatal_error ("error writing to temporary file \"%s\" (%s)",
+      handle, strerror (errno));
+#endif /* !SWAP_TO_XMS */
+/* free the data block (in lower RAM) */
+FreeFarMemory (ptr);
+}
+
+
+
+/*
+   get the objects needed (if they aren't already in memory)
+*/
+
+void SwapInObjects (void)
+{
+if (NeedThings && NumThings > 0 && Things == NULL)
+   Things = (TPtr) SwapIn (ThingsH,
+   			(unsigned long) NumThings * sizeof (struct Thing));
+if (NeedLineDefs && NumLineDefs > 0 && LineDefs == NULL)
+   LineDefs = (LDPtr) SwapIn (LineDefsH,
+   			(unsigned long) NumLineDefs * sizeof (struct LineDef));
+if (NeedSideDefs && NumSideDefs > 0 && SideDefs == NULL)
+   SideDefs = (SDPtr) SwapIn (SideDefsH,
+   			(unsigned long) NumSideDefs * sizeof (struct SideDef));
+if (NeedVertices && NumVertices > 0 && Vertices == NULL)
+   Vertices = (VPtr) SwapIn (VerticesH,
+   			(unsigned long) NumVertices * sizeof (struct Vertex));
+if (NeedSectors && NumSectors > 0 && Sectors == NULL)
+   Sectors = (SPtr) SwapIn (SectorsH,
+   			(unsigned long) NumSectors * sizeof (struct Sector));
+}
+
+
+/*
+   mark the objects that should be in lower RAM
+*/
+
+void ObjectsNeeded (int objtype, ...)
+{
+va_list args;
+
+/* get the list of objects */
+NeedThings = false;
+NeedLineDefs = false;
+NeedSideDefs = false;
+NeedVertices = false;
+NeedSectors = false;
+va_start (args, objtype);
+while (objtype > 0)
+{
+   switch (objtype)
+   {
+   case OBJ_THINGS:
+      NeedThings = true;
+      break;
+   case OBJ_LINEDEFS:
+      NeedLineDefs = true;
+      break;
+   case OBJ_SIDEDEFS:
+      NeedSideDefs = true;
+      break;
+   case OBJ_VERTICES:
+      NeedVertices = true;
+      break;
+   case OBJ_SECTORS:
+      NeedSectors = true;
+      break;
+   }
+   objtype = va_arg (args, int);
+}
+va_end (args);
+/* get the objects if they aren't already in memory */
+SwapInObjects ();
+}
+
+
+
+/*
+   free as much memory as possible by moving some objects out of lower RAM
+*/
+
+void FreeSomeMemory (void)
+{
+/* move everything to secondary storage */
+if (NumSectors > 0 && Sectors != NULL)
+{
+   SwapOut (Sectors, SectorsH,
+   	(unsigned long) NumSectors * sizeof (struct Sector));
+   Sectors = NULL;
+}
+if (NumVertices > 0 && Vertices != NULL)
+{
+   SwapOut (Vertices, VerticesH,
+   	(unsigned long) NumVertices * sizeof (struct Vertex));
+   Vertices = NULL;
+}
+if (NumSideDefs > 0 && SideDefs != NULL)
+{
+   SwapOut (SideDefs, SideDefsH,
+	(unsigned long) NumSideDefs * sizeof (struct SideDef));
+   SideDefs = NULL;
+}
+if (NumLineDefs > 0 && LineDefs != NULL)
+{
+   SwapOut (LineDefs, LineDefsH,
+   	(unsigned long) NumLineDefs * sizeof (struct LineDef));
+   LineDefs = NULL;
+}
+if (NumThings > 0 && Things != NULL)
+{
+   SwapOut (Things, ThingsH,
+   	(unsigned long) NumThings * sizeof (struct Thing));
+   Things = NULL;
+}
+/* re-load the objects that are needed */
+SwapInObjects ();
+}
+
+
+/* end of file */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/t_centre.cc	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,67 @@
+/*
+ *	t_centre.cc
+ *	AYM 1998-11-22
+ */
+
+
+/*
+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 "bitvec.h"
+#include "levels.h"
+#include "selectn.h"
+#include "t_centre.h"
+
+
+/*
+ *	centre_of_things
+ *	Return the coordinates of the centre of a group of things.
+ */
+void centre_of_things (SelPtr list, int *x, int *y)
+{
+SelPtr cur;
+int nitems;
+long x_sum;
+long y_sum;
+
+x_sum = 0;
+y_sum = 0;
+for (nitems = 0, cur = list; cur; cur = cur->next, nitems++)
+   {
+   x_sum += Things[cur->objnum].xpos;
+   y_sum += Things[cur->objnum].ypos;
+   }
+if (nitems == 0)
+   {
+   *x = 0;
+   *y = 0;
+   }
+else
+   {
+   *x = (int) (x_sum / nitems);
+   *y = (int) (y_sum / nitems);
+   }
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/t_centre.h	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,9 @@
+/*
+ *	t_centre.h
+ *	AYM 1998-11-22
+ */
+
+
+void centre_of_things (SelPtr list, int *x, int *y);
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/t_flags.cc	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,69 @@
+/*
+ *	t_flags.cc
+ *	AYM 1998-12-21
+ */
+
+
+/*
+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 "levels.h"
+#include "selectn.h"
+#include "wstructs.h"
+
+
+/*
+ *	frob_things_flags - set/reset/toggle things flags
+ *
+ *	For all the things in <list>, apply the operator <op>
+ *	with the operand <operand> on the flags field.
+ */
+void frob_things_flags (SelPtr list, int op, int operand)
+{
+  SelPtr cur;
+  i16 mask;
+
+  if (op == YO_CLEAR || op == YO_SET || op == YO_TOGGLE)
+    mask = 1 << operand;
+  else
+    mask = operand;
+
+  for (cur = list; cur; cur = cur->next)
+  {
+    if (op == YO_CLEAR)
+      Things[cur->objnum].when &= ~mask;
+    else if (op == YO_SET)
+      Things[cur->objnum].when |= mask;
+    else if (op == YO_TOGGLE)
+      Things[cur->objnum].when ^= mask;
+    else
+    {
+      nf_bug ("frob_things_flags: op=%02X", op);
+      return;
+    }
+  }
+  MadeChanges = 1;
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/t_flags.h	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,8 @@
+/*
+ *	t_flags.h
+ *	AYM 1998-12-22
+ */
+
+
+void frob_things_flags (SelPtr list, int op, int operand);
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/t_prop.cc	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,334 @@
+/*
+ *	t_prop.c
+ *	Thing properties
+ *	Some of this was originally in editobj.c. It was moved here to
+ *	improve overlay granularity (therefore memory consumption).
+ *	AYM 1998-02-07
+ */
+
+
+/*
+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 "entry.h"
+#include "game.h"
+#include "gfx.h"
+#include "levels.h"
+#include "oldmenus.h"
+#include "selectn.h"
+#include "things.h"
+
+
+/*
+ *	Private functions prototypes
+ */
+static int InputThingType (int x0, int y0, int *number);
+static const char *PrintThinggroup (void *ptr);
+static const char *PrintThingdef (void *ptr);
+
+
+/*
+ *	ThingProperties
+ *	Thing properties dialog. Called by EditObjectsInfo. Was part of
+ *	EditObjectsInfo in editobj.c
+ */
+void ThingProperties (int x0, int y0, SelPtr obj)
+{
+char  *menustr[30];
+int    n, val;
+SelPtr cur;
+int    subwin_y0;
+
+for (n = 0; n < 6; n++)
+   menustr[n] = (char *) GetMemory (60);
+sprintf (menustr[5], "Edit thing #%d", obj->objnum);
+sprintf (menustr[0], "Change type          (Current: %s)",
+         get_thing_name (Things[obj->objnum].type));
+sprintf (menustr[1], "Change angle         (Current: %s)",
+         GetAngleName (Things[obj->objnum].angle));
+sprintf (menustr[2], "Change flags         (Current: %s)",
+         GetWhenName (Things[obj->objnum].when));
+sprintf (menustr[3], "Change X position    (Current: %d)",
+         Things[obj->objnum].xpos);
+sprintf (menustr[4], "Change Y position    (Current: %d)",
+         Things[obj->objnum].ypos);
+val = vDisplayMenu (x0, y0, menustr[5],
+   menustr[0], YK_, 0,
+   menustr[1], YK_, 0,
+   menustr[2], YK_, 0,
+   menustr[3], YK_, 0,
+   menustr[4], YK_, 0,
+   NULL);
+for (n = 0; n < 6; n++)
+   FreeMemory (menustr[n]);
+subwin_y0 = y0 + BOX_BORDER + (2 + val) * FONTH;
+switch (val)
+  {
+  case 1:
+     if (! InputThingType (x0, subwin_y0, &val))
+	{
+	for (cur = obj; cur; cur = cur->next)
+	   Things[cur->objnum].type = val;
+	things_types++;
+	MadeChanges = 1;
+	}
+     break;
+
+  case 2:
+     switch (vDisplayMenu (x0 + 42, subwin_y0, "Select angle",
+			  "North",	YK_, 0,
+			  "NorthEast",	YK_, 0,
+			  "East",	YK_, 0,
+			  "SouthEast",	YK_, 0,
+			  "South",	YK_, 0,
+			  "SouthWest",	YK_, 0,
+			  "West",	YK_, 0,
+			  "NorthWest",	YK_, 0,
+			  NULL))
+	{
+	case 1:
+	   for (cur = obj; cur; cur = cur->next)
+	      Things[cur->objnum].angle = 90;
+	   things_angles++;
+	   MadeChanges = 1;
+	   break;
+
+	case 2:
+	   for (cur = obj; cur; cur = cur->next)
+	      Things[cur->objnum].angle = 45;
+	   things_angles++;
+	   MadeChanges = 1;
+	   break;
+
+	case 3:
+	   for (cur = obj; cur; cur = cur->next)
+	      Things[cur->objnum].angle = 0;
+	   things_angles++;
+	   MadeChanges = 1;
+	   break;
+
+	case 4:
+	   for (cur = obj; cur; cur = cur->next)
+	      Things[cur->objnum].angle = 315;
+	   things_angles++;
+	   MadeChanges = 1;
+	   break;
+
+	case 5:
+	   for (cur = obj; cur; cur = cur->next)
+	      Things[cur->objnum].angle = 270;
+	   things_angles++;
+	   MadeChanges = 1;
+	   break;
+
+	case 6:
+	   for (cur = obj; cur; cur = cur->next)
+	      Things[cur->objnum].angle = 225;
+	   things_angles++;
+	   MadeChanges = 1;
+	   break;
+
+	case 7:
+	   for (cur = obj; cur; cur = cur->next)
+	      Things[cur->objnum].angle = 180;
+	   things_angles++;
+	   MadeChanges = 1;
+	   break;
+
+	case 8:
+	   for (cur = obj; cur; cur = cur->next)
+	      Things[cur->objnum].angle = 135;
+	   things_angles++;
+	   MadeChanges = 1;
+	   break;
+	}
+     break;
+
+  case 3:
+     val = vDisplayMenu (x0 + 42, subwin_y0, "Choose the difficulty level(s)",
+			"D12          (Easy only)",		YK_, 0,
+			"D3           (Medium only)",		YK_, 0,
+			"D12, D3      (Easy and Medium)",	YK_, 0,
+			"D45          (Hard only)",		YK_, 0,
+			"D12, D45     (Easy and Hard)",		YK_, 0,
+			"D3, D45      (Medium and Hard)",	YK_, 0,
+			"D12, D3, D45 (Easy, Medium, Hard)",	YK_, 0,
+			"Toggle \"Deaf/Ambush\" bit",		YK_, 0,
+			"Toggle \"Multi-player only\" bit",	YK_, 0,
+			"(Enter number)",			YK_, 0,
+			NULL);
+     switch (val)
+	{
+	case 1:
+	case 2:
+	case 3:
+	case 4:
+	case 5:
+	case 6:
+	case 7:
+	   for (cur = obj; cur; cur = cur->next)
+	      Things[cur->objnum].when = (Things[cur->objnum].when & 0x18) | val;
+	   MadeChanges = 1;
+	   break;
+
+	case 8:
+	   for (cur = obj; cur; cur = cur->next)
+	      Things[cur->objnum].when ^= 0x08;
+	   MadeChanges = 1;
+	   break;
+
+	case 9:
+	   for (cur = obj; cur; cur = cur->next)
+	      Things[cur->objnum].when ^= 0x10;
+	   MadeChanges = 1;
+	   break;
+
+	case 10:
+	   val = InputIntegerValue (x0 + 84,
+              subwin_y0 + BOX_BORDER + (3 + val) * FONTH, 0, 65535,
+	      Things[obj->objnum].when);
+	   if (val != IIV_CANCEL)
+	      {
+	      for (cur = obj; cur; cur = cur->next)
+		 Things[cur->objnum].when = val;
+	      MadeChanges = 1;
+	      }
+	   break;
+	}
+     break;
+
+  case 4:
+     val = InputIntegerValue (x0 + 42, subwin_y0, MapMinX, MapMaxX,
+                              Things[obj->objnum].xpos);
+     if (val != IIV_CANCEL)
+        {
+	n = val - Things[obj->objnum].xpos;
+	for (cur = obj; cur; cur = cur->next)
+	   Things[cur->objnum].xpos += n;
+	MadeChanges = 1;
+        }
+     break;
+
+  case 5:
+     val = InputIntegerValue (x0 + 42, subwin_y0, MapMinY, MapMaxY,
+                              Things[obj->objnum].ypos);
+     if (val != IIV_CANCEL)
+        {
+	n = val - Things[obj->objnum].ypos;
+	for (cur = obj; cur; cur = cur->next)
+	   Things[cur->objnum].ypos += n;
+	MadeChanges = 1;
+        }
+     break;
+  }
+}
+
+
+/*
+ *	InputThingType
+ *	Let the user select a thing number and return it.
+ *	Returns 0 if OK, <>0 if cancelled
+ */
+static int InputThingType (int x0, int y0, int *number)
+{
+int         r;
+int         tgno = 0;
+char        tg; 
+al_llist_t *list = NULL;
+
+for (;;)
+   {
+   /* First let user select a thinggroup */
+   if (DisplayMenuList (x0+42, y0, "Select group", thinggroup,
+    PrintThinggroup, &tgno) < 0)
+      return 1;
+   if (al_lseek (thinggroup, tgno, SEEK_SET))
+      fatal_error ("%s ITT1 (%s)", msg_unexpected, al_astrerror (al_aerrno));
+   tg = CUR_THINGGROUP->thinggroup;
+
+   /* KLUDGE: Special thinggroup THING_FREE means "enter number".
+      Don't look for this thinggroup in the .ygd file : LoadGameDefs()
+      creates it manually. */
+   if (tg == THING_FREE)
+      {
+      /* FIXME should be unsigned! should accept hex. */
+      *number = InputIntegerValue (x0+84, y0 + BOX_BORDER + (3 + tgno) * FONTH,
+	 -32768, 32767, 0);
+      if (*number != IIV_CANCEL)
+	 break;
+      goto again;
+      }
+     
+   /* Then build a list of pointers on all things that have this
+      thinggroup and let user select one. */
+   list = al_lcreate (sizeof (void *));
+   for (al_lrewind (thingdef); ! al_leol (thingdef); al_lstep (thingdef))
+      if (CUR_THINGDEF->thinggroup == tg)
+	 {
+	 void *ptr = CUR_THINGDEF;
+	 al_lwrite (list, &ptr);
+	 }
+   r = DisplayMenuList (x0+84, y0 + BOX_BORDER + (3 + tgno) * FONTH,
+      "Select thing", list, PrintThingdef, NULL);
+   if (r < 0)
+      goto again;
+   if (al_lseek (list, r, SEEK_SET))
+      fatal_error ("%s ITT2 (%s)", msg_unexpected, al_astrerror (al_aerrno));
+   *number = (*((thingdef_t **) al_lptr (list)))->number;
+   al_ldiscard (list);
+   break;
+
+   again :
+   ;
+   /* DrawMap (OBJ_THINGS, 0, 0); FIXME! */
+   }
+return 0;
+}
+
+
+/*
+ *	PrintThinggroup
+ *	Used by DisplayMenuList when called by InputThingType
+ */
+static const char *PrintThinggroup (void *ptr)
+{
+if (ptr == NULL)
+   return "PrintThinggroup: (null)";
+return ((thinggroup_t *)ptr)->desc;
+}
+
+
+/*
+ *	PrintThingdef
+ *	Used by DisplayMenuList when called by InputThingType
+ */
+static const char *PrintThingdef (void *ptr)
+{
+if (ptr == NULL)
+   return "PrintThingdef: (null)";
+return (*((thingdef_t **)ptr))->desc;
+}
+
+
+/* end of file */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/t_spin.cc	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,57 @@
+/*
+ *	t_spin.cc
+ *	AYM 1998-12-06
+ */
+
+
+/*
+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 "levels.h"
+#include "selectn.h"
+#include "t_spin.h"
+
+
+/*
+ *	spin_thing - change the angle of things
+ */
+void spin_things (SelPtr obj, int degrees)
+{
+  SelPtr cur;
+
+  if (! obj)
+    return;
+  for (cur = obj; cur; cur = cur->next)
+  {
+    Things[cur->objnum].angle += degrees;
+    while (Things[cur->objnum].angle >= 360)	// No we can't use %
+      Things[cur->objnum].angle -= 360;
+    while (Things[cur->objnum].angle < 0)	// (negatives...)
+      Things[cur->objnum].angle += 360;
+  }
+  things_angles++;
+  MadeChanges = 1;
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/t_spin.h	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,9 @@
+/*
+ *	t_spin.h
+ *	AYM 1998-12-06
+ */
+
+
+void spin_things (SelPtr obj, int degrees);
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/textures.cc	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,594 @@
+/*
+ *	textures.cc
+ *	Trevor Phillips, RQ and Christian Johannes Schladetsch
+ *	sometime in 1994.
+ */
+
+
+/*
+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"
+#ifdef Y_X11
+#include <X11/Xlib.h>
+#endif
+#include "dialog.h"
+#include "game.h"      /* yg_picture_format */
+#include "gfx.h"
+#include "lists.h"
+#include "patchdir.h"
+#include "pic2img.h"
+#include "sticker.h"
+#include "textures.h"
+#include "wadfile.h"
+#include "wads.h"
+#include "wstructs.h"
+
+
+/*
+   display a wall texture ("TEXTURE1" or "TEXTURE2" object)
+   at coords c->x0, c->y0
+*/
+void DisplayWallTexture (hookfunc_comm_t *c)
+{
+MDirPtr  dir = 0;	// Main directory pointer to the TEXTURE* entries
+int      n;		// General counter
+i16      width, height;	// Size of the texture
+i16      npatches;	// Number of patches in the textures
+i32      numtex;	// number of texture names in TEXTURE* list
+i32      texofs;	// Offset in the wad file to the texture data
+char     tname[WAD_TEX_NAME + 1];	/* texture name */
+char     picname[WAD_PIC_NAME + 1];	/* wall patch name */
+bool     have_dummy_bytes;
+int      header_size;
+int      item_size;
+
+// So that, on failure, the caller clears the display area
+c->disp_x0 = c->x1;
+c->disp_y0 = c->y1;
+c->disp_x1 = c->x0;
+c->disp_y1 = c->y0;
+
+// Iwad-dependant details
+if (yg_texture_format == YGTF_NAMELESS)
+   {
+   have_dummy_bytes = true;
+   header_size      = 14;
+   item_size        = 10;
+   }
+else if (yg_texture_format == YGTF_NORMAL)
+   {
+   have_dummy_bytes = true;
+   header_size      = 14;
+   item_size        = 10;
+   }
+else if (yg_texture_format == YGTF_STRIFE11)
+   {
+   have_dummy_bytes = false;
+   header_size      = 10;
+   item_size        = 6;
+   }
+else
+   {
+   nf_bug ("Bad texture format %d.", (int) yg_texture_format);
+   return;
+   }
+
+#ifndef Y_X11
+if (have_key ())
+   return;				// Speedup
+#endif
+
+// Offset for texture we want
+texofs = 0;
+// Doom alpha 0.4 : "TEXTURES", no names
+if (yg_texture_lumps == YGTL_TEXTURES && yg_texture_format == YGTF_NAMELESS)
+   {
+   const char *lump_name = "TEXTURES";
+   dir = FindMasterDir (MasterDir, lump_name);
+   if (dir != NULL)
+      {
+      const Wad_file *wf = dir->wadfile;
+      wf->seek (dir->dir.start);
+      if (wf->error ())
+	 {
+	 warn ("%s: can't seek to lump\n", lump_name);
+	 goto alpha04_done;
+	 }
+      wf->read_i32 (&numtex);
+      if (wf->error ())
+	 {
+	 warn ("%s: error reading texture count\n", lump_name);
+	 goto alpha04_done;
+	 }
+      if (WAD_TEX_NAME < 7) nf_bug ("WAD_TEX_NAME too small");  // Sanity
+      if (! y_strnicmp (c->name, "TEX", 3)
+	    && isdigit (c->name[3])
+	    && isdigit (c->name[4])
+	    && isdigit (c->name[5])
+	    && isdigit (c->name[6])
+	    && c->name[7] == '\0')
+	 {
+	 long num;
+	 if (sscanf (c->name + 3, "%4ld", &num) == 1
+	       && num >= 0 && num < numtex)
+	    {
+	    wf->seek (dir->dir.start + 4 + 4 * num);
+	    if (wf->error ())
+	       {
+	       // FIXME print name of offending texture (or #)
+	       warn ("%s: can't seek to offsets table entry\n", lump_name);
+	       goto alpha04_done;
+	       }
+	    wf->read_i32 (&texofs);
+	    if (wf->error ())
+	       {
+	       warn ("%s: error reading texture offset\n", lump_name);
+	       goto alpha04_done;
+	       }
+	    texofs += dir->dir.start;
+	    }
+	 }
+      }
+   alpha04_done:
+   ;
+   }
+// Doom alpha 0.5 : only "TEXTURES"
+else if (yg_texture_lumps == YGTL_TEXTURES
+   && (yg_texture_format == YGTF_NORMAL || yg_texture_format == YGTF_STRIFE11))
+   {
+   const char *lump_name = "TEXTURES";
+   dir = FindMasterDir (MasterDir, lump_name);
+   if (dir != NULL)  // (Theoretically, it should always exist)
+      {
+      i32 *offsets = NULL;  // Array of offsets to texture names
+      const Wad_file *wf = dir->wadfile;
+
+      wf->seek (dir->dir.start);
+      if (wf->error ())
+	 {
+	 warn ("%s: can't seek to lump\n", lump_name);
+	 goto textures_done;
+	 }
+      wf->read_i32 (&numtex);
+      if (wf->error ())
+	 {
+	 warn ("%s: error reading texture count\n", lump_name);
+	 goto textures_done;
+	 }
+      // Read in the offsets for texture1 names and info
+      offsets = (i32 *) GetMemory ((long) numtex * 4);
+      wf->read_i32 (offsets, numtex);
+      if (wf->error ())
+	 {
+	 warn ("%s: error reading offsets table\n", lump_name);
+	 goto textures_done;
+	 }
+      for (long n = 0; n < numtex && !texofs; n++)
+	 {
+	 wf->seek (dir->dir.start + offsets[n]);
+	 if (wf->error ())
+	    {
+	    warn ("%s: error seeking to definition of texture #%ld\n",
+	      lump_name, n);
+	    break;
+	    }
+	 wf->read_bytes (&tname, WAD_TEX_NAME);
+	 if (wf->error ())
+	    {
+	    warn ("%s: error reading name of texture #%ld\n", lump_name, n);
+	    break;
+	    }
+	 if (!y_strnicmp (tname, c->name, WAD_TEX_NAME))
+	    texofs = dir->dir.start + offsets[n];
+	 }
+      textures_done:
+      if (offsets != NULL)
+	 FreeMemory (offsets);
+      }
+   }
+// Other iwads : "TEXTURE1" and "TEXTURE2"
+else if (yg_texture_lumps == YGTL_NORMAL
+   && (yg_texture_format == YGTF_NORMAL || yg_texture_format == YGTF_STRIFE11))
+   {
+   // Is it in TEXTURE1 ?
+   {
+   const char *lump_name = "TEXTURE1";
+   dir = FindMasterDir (MasterDir, lump_name);
+   if (dir != NULL)  // (Theoretically, it should always exist)
+      {
+      const Wad_file *wf = dir->wadfile;
+      i32 *offsets = NULL;  // Array of offsets to texture names
+
+      wf->seek (dir->dir.start);
+      if (wf->error ())
+	 {
+	 warn ("%s: can't seek to lump\n", lump_name);
+	 goto texture1_done;
+	 }
+      wf->read_i32 (&numtex);
+      if (wf->error ())
+	 {
+	 warn ("%s: error reading texture count\n", lump_name);
+	 goto texture1_done;
+	 }
+      // Read in the offsets for texture1 names and info
+      offsets = (i32 *) GetMemory ((long) numtex * 4);
+      wf->read_i32 (offsets, numtex);
+      if (wf->error ())
+	 {
+	 warn ("%s: error reading offsets table\n", lump_name);
+	 goto texture1_done;
+	 }
+      for (long n = 0; n < numtex && !texofs; n++)
+	 {
+	 wf->seek (dir->dir.start + offsets[n]);
+	 if (wf->error ())
+	    {
+	    warn ("%s: error seeking to definition of texture #%ld\n",
+	      lump_name, n);
+	    break;
+	    }
+	 wf->read_bytes (&tname, WAD_TEX_NAME);
+	 if (wf->error ())
+	    {
+	    warn ("%s: error reading name of texture #%ld\n", lump_name, n);
+	    break;
+	    }
+	 if (!y_strnicmp (tname, c->name, WAD_TEX_NAME))
+	    texofs = dir->dir.start + offsets[n];
+	 }
+      texture1_done:
+      if (offsets != NULL)
+	 FreeMemory (offsets);
+      }
+   }
+   // Well, then is it in TEXTURE2 ?
+   if (texofs == 0)
+      {
+      const char *lump_name = "TEXTURE2";
+      i32 *offsets = NULL;  // Array of offsets to texture names
+
+      dir = FindMasterDir (MasterDir, lump_name);
+      if (dir != NULL)  // Doom II has no TEXTURE2
+	 {
+	 const Wad_file * wf = dir->wadfile;
+	 wf->seek (dir->dir.start);
+	 if (wf->error ())
+	    {
+	    warn ("%s: can't seek to lump\n", lump_name);
+	    goto texture2_done;
+	    }
+	 wf->read_i32 (&numtex);
+	 if (wf->error ())
+	    {
+	    warn ("%s: error reading texture count\n", lump_name);
+	    goto texture2_done;
+	    }
+	 // Read in the offsets for TEXTURE2 names
+	 offsets = (i32 *) GetMemory ((long) numtex * 4);
+	 wf->read_i32 (offsets, numtex);
+	 if (wf->error ())
+	    {
+	    warn ("%s: error reading offsets table\n", lump_name);
+	    goto texture2_done;
+	    }
+	 for (long n = 0; n < numtex && !texofs; n++)
+	    {
+	    wf->seek (dir->dir.start + offsets[n]);
+	    if (wf->error ())
+	       {
+	       warn ("%s: error seeking to definition of texture #%ld\n",
+		 lump_name, n);
+	       break;
+	       }
+	    wf->read_bytes (&tname, WAD_TEX_NAME);
+	    if (wf->error ())
+	       {
+	       warn ("%s: error reading name of texture #%ld\n", lump_name, n);
+	       break;
+	       }
+	    if (!y_strnicmp (tname, c->name, WAD_TEX_NAME))
+	       texofs = dir->dir.start + offsets[n];
+	    }
+	 texture2_done:
+	 if (offsets != NULL)
+	    FreeMemory (offsets);
+	 }
+      }
+   }
+else
+   nf_bug ("Invalid texture_format/texture_lumps combination.");
+
+// Texture name not found
+if (texofs == 0)
+   return;
+
+// Read the info for this texture
+i32 header_ofs;
+if (yg_texture_format == YGTF_NAMELESS)
+   header_ofs = texofs;
+else
+   header_ofs = texofs + WAD_TEX_NAME;
+dir->wadfile->seek     (header_ofs + 4);
+// FIXME
+dir->wadfile->read_i16 (&width);
+// FIXME
+dir->wadfile->read_i16 (&height);
+// FIXME
+if (have_dummy_bytes)
+   {
+   i16 dummy;
+   dir->wadfile->read_i16 (&dummy);
+   dir->wadfile->read_i16 (&dummy);
+   }
+dir->wadfile->read_i16 (&npatches);
+// FIXME
+
+c->width    = width;
+c->height   = height;
+c->npatches = npatches;
+c->flags   |= HOOK_SIZE_VALID | HOOK_DISP_SIZE;
+
+/* Clip the texture to size. Done *after* setting c->width and
+   c->height so that the selector shows the unclipped size. */
+width  = y_min (width,  c->x1 - c->x0 + 1);
+height = y_min (height, c->y1 - c->y0 + 1);
+
+#ifndef Y_X11
+if (have_key ())
+   return;				// Speedup
+#endif
+
+#ifdef Y_BGI
+// Not really necessary, except when xofs or yofs < 0
+setviewport (c->x0, c->y0, c->x1, c->y1, 1);
+#endif  /* FIXME ! */
+
+// Compose the texture
+c->img.resize (width, height);
+c->img.set_opaque (false);
+
+/* Paste onto the buffer all the patches that the texture is
+   made of. Unless c->npatches is non-zero, in which case we
+   paste only the first maxpatches ones. */
+int maxpatches = npatches;
+if (c->maxpatches != 0 && c->maxpatches <= npatches)
+   maxpatches = c->maxpatches;
+for (n = 0; n < maxpatches; n++)
+   {
+   hookfunc_comm_t subc;
+   i16 xofs, yofs;	// Offset in texture space for the patch
+   i16 pnameind;	// Index of patch in PNAMES
+
+   dir->wadfile->seek (header_ofs + header_size + (long) n * item_size);
+   dir->wadfile->read_i16 (&xofs);
+   dir->wadfile->read_i16 (&yofs);
+   dir->wadfile->read_i16 (&pnameind);
+   if (have_dummy_bytes)
+      {
+      i16 stepdir;
+      i16 colormap;
+      dir->wadfile->read_i16 (&stepdir);   // Always 1, unused.
+      dir->wadfile->read_i16 (&colormap);  // Always 0, unused.
+      }
+
+   /* AYM 1998-08-08: Yes, that's weird but that's what Doom
+      does. Without these two lines, the few textures that have
+      patches with negative y-offsets (BIGDOOR7, SKY1, TEKWALL1,
+      TEKWALL5 and a few others) would not look in the texture
+      viewer quite like in Doom. This should be mentioned in
+      the UDS, by the way. */
+   if (yofs < 0)
+      yofs = 0;
+
+   Lump_loc loc;
+   {
+     wad_pic_name_t *name = patch_dir.name_for_num (pnameind);
+     if (name == 0)
+       {
+       warn ("texture \"%.*s\": patch %2d has bad index %d.\n",
+	  WAD_TEX_NAME, tname, (int) n, (int) pnameind);
+       continue;
+       }
+     patch_dir.loc_by_name ((const char *) *name, loc);
+     *picname = '\0';
+     strncat (picname, (const char *) *name, sizeof picname - 1);
+#ifdef DEBUG
+     printf ("Texture \"%.*s\": Patch %2d: #%3d %-8.8s (%d, %d)\n",
+       c->name, (int) n, (int) pnameind, picname, (int) xofs, (int) yofs);
+#endif
+   }
+
+#ifdef Y_BGI
+   /* AYM 1998-07-11
+      Is it normal to set x0 and y0 to potentially negative values ? */
+   // coords changed because of the "setviewport"
+   subc.x0 = xofs;
+   subc.y0 = yofs;
+   subc.x1 = c->x1 - c->x0;
+   subc.y1 = c->y1 - c->y0;
+#else
+   subc.x0 = y_max (c->x0, c->x0 + xofs);
+   subc.y0 = y_min (c->y0, c->y0 + yofs);
+   subc.x1 = c->x1;
+   subc.x1 = c->y1;
+#endif
+   subc.name = picname;
+
+   if (LoadPicture (c->img, picname, loc, xofs, yofs, 0, 0))
+      warn ("texture \"%.*s\": patch \"%.*s\" not found.\n",
+	  WAD_TEX_NAME, tname, WAD_PIC_NAME, picname);
+   }
+
+// Display the texture
+Sticker sticker (c->img, true);		// Use opaque because it's faster
+sticker.draw (drw, 't', c->x0, c->y0);
+c->flags |= HOOK_DRAWN;
+c->disp_x0 = c->x0 + c->xofs;
+c->disp_y0 = c->y0 + c->yofs;
+c->disp_x1 = c->disp_x0 + width - 1;
+c->disp_y1 = c->disp_y0 + height - 1;
+
+#ifdef Y_BGI
+// Restore the normal viewport
+setviewport (0, 0, ScrMaxX, ScrMaxY, 1);
+#endif  /* FIXME ! */
+}
+
+
+/*
+   Function to get the size of a wall texture
+*/
+void GetWallTextureSize (i16 *width, i16 *height, const char *texname)
+{
+MDirPtr  dir = 0;			// Pointer in main directory to texname
+i32    *offsets;			// Array of offsets to texture names
+int      n;				// General counter
+i32      numtex;			// Number of texture names in TEXTURE*
+i32      texofs;			// Offset in wad for the texture data
+char     tname[WAD_TEX_NAME + 1];	// Texture name
+
+// Offset for texture we want
+texofs = 0;
+// Search for texname in TEXTURE1 (or TEXTURES)
+if (yg_texture_lumps == YGTL_TEXTURES && yg_texture_format == YGTF_NAMELESS)
+   {
+   dir = FindMasterDir (MasterDir, "TEXTURES");
+   if (dir != NULL)
+      {
+      dir->wadfile->seek (dir->dir.start);
+      dir->wadfile->read_i32 (&numtex);
+      if (WAD_TEX_NAME < 7) nf_bug ("WAD_TEX_NAME too small");  // Sanity
+      if (! y_strnicmp (texname, "TEX", 3)
+	    && isdigit (texname[3])
+	    && isdigit (texname[4])
+	    && isdigit (texname[5])
+	    && isdigit (texname[6])
+	    && texname[7] == '\0')
+	 {
+	 long num;
+	 if (sscanf (texname + 3, "%4ld", &num) == 1
+	       && num >= 0 && num < numtex)
+	    {
+	    dir->wadfile->seek (dir->dir.start + 4 + 4 * num);
+	    dir->wadfile->read_i32 (&texofs);
+	    }
+	 }
+      }
+   }
+else if (yg_texture_format == YGTF_NORMAL
+    || yg_texture_format == YGTF_STRIFE11)
+   {
+   if (yg_texture_lumps == YGTL_TEXTURES)
+      dir = FindMasterDir (MasterDir, "TEXTURES");  // Doom alpha 0.5
+   else if (yg_texture_lumps == YGTL_NORMAL)
+      dir = FindMasterDir (MasterDir, "TEXTURE1");
+   else
+      {
+      dir = 0;
+      nf_bug ("Invalid texture_format/texture_lumps combination.");
+      }
+   if (dir != NULL)
+      {
+      dir->wadfile->seek (dir->dir.start);
+      dir->wadfile->read_i32 (&numtex);
+      // Read in the offsets for texture1 names and info
+      offsets = (i32 *) GetMemory ((long) numtex * 4);
+      dir->wadfile->read_i32 (offsets, numtex);
+      for (n = 0; n < numtex && !texofs; n++)
+	 {
+	 dir->wadfile->seek (dir->dir.start + offsets[n]);
+	 dir->wadfile->read_bytes (&tname, WAD_TEX_NAME);
+	 if (!y_strnicmp (tname, texname, WAD_TEX_NAME))
+	    texofs = dir->dir.start + offsets[n];
+	 }
+      FreeMemory (offsets);
+      }
+   if (texofs == 0 && yg_texture_lumps == YGTL_NORMAL)
+      {
+      // Search for texname in TEXTURE2
+      dir = FindMasterDir (MasterDir, "TEXTURE2");
+      if (dir != NULL)  // Doom II has no TEXTURE2
+	 {
+	 dir->wadfile->seek (dir->dir.start);
+	 dir->wadfile->read_i32 (&numtex);
+	 // Read in the offsets for texture2 names
+	 offsets = (i32 *) GetMemory ((long) numtex * 4);
+	 dir->wadfile->read_i32 (offsets);
+	 for (n = 0; n < numtex && !texofs; n++)
+	    {
+	    dir->wadfile->seek (dir->dir.start + offsets[n]);
+	    dir->wadfile->read_bytes (&tname, WAD_TEX_NAME);
+	    if (!y_strnicmp (tname, texname, WAD_TEX_NAME))
+	       texofs = dir->dir.start + offsets[n];
+	    }
+	 FreeMemory (offsets);
+	 }
+      }
+   }
+else
+   nf_bug ("Invalid texture_format/texture_lumps combination.");
+
+if (texofs != 0)
+   {
+   // Read the info for this texture
+   if (yg_texture_format == YGTF_NAMELESS)
+      dir->wadfile->seek (texofs + 4L);
+   else
+      dir->wadfile->seek (texofs + 12L);
+   dir->wadfile->read_i16 (width);
+   dir->wadfile->read_i16 (height);
+   }
+else
+   {
+   // Texture data not found
+   *width  = -1;
+   *height = -1;
+   }
+}
+
+
+/*
+   choose a wall texture
+*/
+void ChooseWallTexture (int x0, int y0, const char *prompt, int listsize,
+   char **list, char *name)
+{
+HideMousePointer ();
+
+SwitchToVGA256 ();
+/* If we only have a 320x200x256 VGA driver, we must change x0 and y0.
+   Yuck! */
+if (GfxMode > -2)
+   {
+   x0 = 0;
+   y0 = -1;
+   }
+InputNameFromListWithFunc (x0, y0, prompt, listsize, list, 9, name,
+  512, 256, DisplayWallTexture);
+SwitchToVGA16 ();
+
+ShowMousePointer ();
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/textures.h	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,20 @@
+/*
+ *	textures.h
+ *	AYM 2000-04-29
+ */
+
+
+#ifndef YH_TEXTURES  /* DO NOT ADD ANYTHING BEFORE THIS LINE */
+#define YH_TEXTURES
+
+
+#include "lists.h"
+
+
+/* textures.cc */
+void DisplayPic (hookfunc_comm_t *c);
+void ChooseWallTexture (int, int, const char *, int, char **, char *);
+void GetWallTextureSize (i16 *, i16 *, const char *);
+
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/things.cc	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,394 @@
+/*
+ *	things.cc
+ *	Misc things routines.
+ *	BW & RQ sometime in 1993 or 1994.
+ */
+
+
+/*
+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.
+*/
+
+
+#define YC_THINGS
+
+
+#include "yadex.h"
+#include "game.h"
+#include "things.h"
+
+
+// This is the structure of a table of things attributes.
+// In this table, things are sorted by increasing number.
+// It is searched in a dichotomic fashion by get_thing_*().
+// This table is only here for speed.
+typedef struct
+  {
+  wad_ttype_t type;
+  char		flags;
+  short         radius;
+  acolour_t     colour;
+  const char    *desc;
+  const char	*sprite;
+  } thing_attributes_t;
+
+static thing_attributes_t *things_table;
+static size_t nthings;
+int _max_radius;
+static size_t last_table_idx = (size_t) -1;
+
+
+static int things_table_cmp (const void *a, const void *b);
+
+
+static const int default_radius = 16;
+
+
+/*
+ *	create_things_table
+ *	Build things_table, a table of things attributes
+ *	that's used by get_thing_*() to speed things up.
+ *	Call delete_things_table to delete that table.
+ */
+void create_things_table ()
+{
+size_t n;
+
+_max_radius = default_radius;
+nthings = al_lcount (thingdef);
+if (nthings == 0)
+   {
+   things_table = NULL;
+   return;
+   }
+things_table = (thing_attributes_t *) malloc (nthings * sizeof *things_table);
+if (! things_table)
+   fatal_error ("Not enough memory");
+for (al_lrewind (thingdef), n = 0; n < nthings; al_lstep (thingdef), n++)
+   {
+   things_table[n].type   = CUR_THINGDEF->number;
+   things_table[n].flags  = CUR_THINGDEF->flags;
+   things_table[n].radius = CUR_THINGDEF->radius;
+   _max_radius = y_max (_max_radius, CUR_THINGDEF->radius);
+
+   // Fetch the app colour no. for the thinggroup
+   for (al_lrewind (thinggroup); ! al_leol (thinggroup); al_lstep (thinggroup))
+      {
+      if (CUR_THINGGROUP  /* don't segfault if zero thinggroup ! */
+       && CUR_THINGGROUP->thinggroup == CUR_THINGDEF->thinggroup)
+	 {
+	 things_table[n].colour = CUR_THINGGROUP->acn;
+	 break;
+	 }
+      }
+
+   things_table[n].desc   = CUR_THINGDEF->desc;
+   things_table[n].sprite = CUR_THINGDEF->sprite;
+   }
+
+// Sort the table by increasing thing type
+qsort (things_table, nthings, sizeof *things_table, things_table_cmp);
+
+#if 0
+printf ("Type  Colour Radius Desc\n");
+for (n = 0; n < nthings; n++)
+   printf ("%5d %-6d %3d    %s\n",
+      things_table[n].type,
+      things_table[n].colour,
+      things_table[n].radius,
+      things_table[n].desc);
+#endif
+}
+
+
+/*
+ *	delete_things_table
+ *	Free what create_things_table() allocated.
+ */
+void delete_things_table (void)
+{
+if (things_table)
+   {
+   free (things_table);
+   nthings = 0;
+   }
+}
+
+
+/*
+ *	things_table_cmp
+ *	Used by create_things_table() to sort the table
+ *	by increasing THING type.
+ */
+static int things_table_cmp (const void *a, const void *b)
+{
+return ((const thing_attributes_t *) a)->type
+     - ((const thing_attributes_t *) b)->type;
+}
+
+
+/*
+ *	lookup_thing
+ *	Does a binary search in things_table for the thing of type <type>.
+ *	If succeeds, returns the index of the thing.
+ *	If fails, returns ((size_t) -1).
+ *	To further speed things up, the last index found is kept
+ *	between invocations in a static variable. Thus, if several
+ *	attributes of the same thing type are queried in a row,
+ *	the table search is done only once.
+ */
+inline int lookup_thing (wad_ttype_t type)
+{
+if (last_table_idx < nthings && things_table[last_table_idx].type == type)
+   return last_table_idx;
+
+if (things_table == NULL)
+   return (size_t) -1;
+
+size_t nmin = 0;
+size_t nmax = nthings - 1;
+for (;;)
+   {
+   last_table_idx = (nmin + nmax) / 2;
+   if (type > things_table[last_table_idx].type)
+      {
+      if (nmin >= nmax)
+         break;
+      nmin = last_table_idx + 1;
+      }
+   else if (type < things_table[last_table_idx].type)
+      {
+      if (nmin >= nmax)
+         break;
+      if (last_table_idx < 1)
+         break;
+      nmax = last_table_idx - 1;
+      }
+   else
+      return last_table_idx;
+   }
+return (size_t) -1;
+}
+
+
+/*
+ *	is_thing_type - is given type valid (i.e. defined in the ygd)
+ *
+ *	Return true if the thing is defined, false otherwise.
+ */
+bool is_thing_type (wad_ttype_t type)
+{
+size_t table_idx = lookup_thing (type);
+return table_idx < nthings;
+}
+
+
+/*
+ *	get_thing_colour - return the colour of the thing of given type.
+ *
+ *	Return the colour. If the 
+ */
+acolour_t get_thing_colour (wad_ttype_t type)
+{
+size_t table_idx = lookup_thing (type);
+if (table_idx == (size_t) -1)
+   return LIGHTCYAN;  // Not found.
+else
+   return things_table[table_idx].colour;
+}
+
+
+/*
+ *	get_thing_name - return the description of the thing of given type.
+ */
+const char *get_thing_name (wad_ttype_t type)
+{
+size_t table_idx = lookup_thing (type);
+if (table_idx == (size_t) -1)
+   {
+   static char buf[20];
+   sprintf (buf, "UNKNOWN (%d)", type);  // Not found.
+   return buf;
+   }
+else
+   return things_table[table_idx].desc;
+}
+
+
+/*
+ *	get_thing_sprite
+ *	Return the root of the sprite name for the thing of given type.
+ */
+const char *get_thing_sprite (wad_ttype_t type)
+{
+size_t table_idx = lookup_thing (type);
+if (table_idx == (size_t) -1)
+   return NULL;  // Not found
+else
+   return things_table[table_idx].sprite;
+}
+
+
+/*
+ *	get_thing_flags
+ *	Return the flags for the thing of given type.
+ */
+char get_thing_flags (wad_ttype_t type)
+{
+size_t table_idx = lookup_thing (type);
+if (table_idx == (size_t) -1)
+   return 0;  // Not found
+else
+   return things_table[table_idx].flags;
+}
+
+
+/*
+ *	get_thing_radius
+ *	Return the radius of the thing of given type.
+ */
+int get_thing_radius (wad_ttype_t type)
+{
+size_t table_idx = lookup_thing (type);
+if (table_idx == (size_t) -1)
+   return default_radius;  // Not found.
+else
+   return things_table[table_idx].radius;
+}
+
+
+/*
+ *	get_max_thing_radius
+ *	Return the radius of the largest thing that exists.
+ *	This is a speedup function, used by GetCurObject()
+ *	to avoid calculating the distance for the things
+ *	that are obviously too far away.
+ */
+
+/* It's now inlined in things.h
+int get_max_thing_radius ()
+{
+return _max_radius;
+}
+*/
+
+
+/*
+ *	GetAngleName
+ *	Get the name of the angle
+ */
+const char *GetAngleName (int angle)
+{
+static char buf[30];
+
+switch (angle)
+   {
+   case 0:
+      return "East";
+   case 45:
+      return "North-east";
+   case 90:
+      return "North";
+   case 135:
+      return "North-west";
+   case 180:
+      return "West";
+   case 225:
+      return "South-west";
+   case 270:
+      return "South";
+   case 315:
+      return "South-east";
+   }
+sprintf (buf, "ILLEGAL (%d)", angle);
+return buf;
+}
+
+
+/*
+ *	GetWhenName
+ *	get string of when something will appear
+ */
+const char *GetWhenName (int when)
+{
+static char buf[16+3+1];
+// "N" is a Boom extension ("not in deathmatch")
+// "C" is a Boom extension ("not in cooperative")
+// "F" is an MBF extension ("friendly")
+const char *flag_chars = "????" "????" "FCNM" "D431";
+int n;
+
+char *b = buf;
+for (n = 0; n < 16; n++)
+   {
+   if (n != 0 && n % 4 == 0)
+      *b++ = ' ';
+   if (when & (0x8000u >> n))
+      *b++ = flag_chars[n];
+   else
+      *b++ = '-';
+   }
+*b = '\0';
+return buf;
+
+#if 0
+static char buf[30];
+char *ptr = buf;
+*ptr = '\0';
+if (when & 0x01)
+   {
+   strcpy (ptr, "D12");
+   ptr += 3;
+   }
+if (when & 0x02)
+   {
+   if (ptr != buf)
+      *ptr++ = ' ';
+   strcpy (ptr, "D3");
+   ptr += 2;
+   }
+if (when & 0x04)
+   {
+   if (ptr != buf)
+      *ptr++ = ' ';
+   strcpy (ptr, "D45");
+   ptr += 3;
+   }
+if (when & 0x08)
+   {
+   if (ptr != buf)
+      *ptr++ = ' ';
+   strcpy (ptr, "Deaf");
+   ptr += 4;
+   }
+if (when & 0x10)
+   {
+   if (ptr != buf)
+      *ptr++ = ' ';
+   strcpy (ptr, "Multi");
+   ptr += 5;
+   }
+return buf;
+#endif
+}
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/things.h	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,56 @@
+/*
+ *	things.h
+ *	Header for things.cc
+ *	BW & RQ sometime in 1993 or 1994.
+ */
+
+
+#ifndef YH_THINGS  /* Prevent multiple inclusion */
+#define YH_THINGS  /* Prevent multiple inclusion */
+
+
+#include "wstructs.h"
+
+
+/* starting areas */
+#define THING_PLAYER1         1
+#define THING_PLAYER2         2
+#define THING_PLAYER3         3
+#define THING_PLAYER4         4
+#define THING_DEATHMATCH      11
+
+
+extern
+#ifndef YC_THINGS
+const
+#endif
+int _max_radius;
+
+
+void        create_things_table ();
+void        delete_things_table ();
+bool        is_thing_type    (wad_ttype_t type);
+acolour_t   get_thing_colour (wad_ttype_t type);
+const char *get_thing_name   (wad_ttype_t type);
+const char *get_thing_sprite (wad_ttype_t type);
+char        get_thing_flags  (wad_ttype_t type);
+int         get_thing_radius (wad_ttype_t type);
+inline int  get_max_thing_radius () { return _max_radius; }
+const char *GetAngleName (int);
+const char *GetWhenName (int);
+
+
+/*
+ *	angle_to_direction - convert angle to direction (0-7)
+ *
+ *	Return a value that is guaranteed to be within [0-7].
+ */
+inline int angle_to_direction (wad_tangle_t angle)
+{
+  return ((unsigned) angle / 45) % 8;
+}
+
+
+#endif  /* Prevent multiple inclusion */
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/trace.cc	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,50 @@
+/*
+ *	trace.cc
+ *	Selective tracing system
+ *	AYM 1999-11-30
+ */
+
+
+/*
+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 "trace.h"
+
+
+// FIXME stopgap
+void trace (const char *domain, const char *fmt, ...)
+{
+  if (verbose)
+  {
+    va_list args;
+
+    fprintf (stdout, "%s: ", domain);
+    va_start (args, fmt);
+    vprintf (fmt, args);
+    va_end (args);
+    putchar ('\n');
+  }
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/trace.h	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,39 @@
+/*
+ *	trace.h
+ *	Selective tracing system
+ *	AYM 1999-11-30
+ */
+
+
+/*
+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.
+*/
+
+
+#ifndef YH_TRACE
+#define YH_TRACE
+
+
+// FIXME stopgap
+void trace (const char *domain, const char *fmt, ...);
+
+
+#endif  /* DO NOT ADD ANYTHING AFTER THIS LINE */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/v_centre.cc	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,99 @@
+/*
+ *	v_centre.cc
+ *	AYM 1998-11-22
+ */
+
+
+/*
+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 "bitvec.h"
+#include "levels.h"
+#include "selectn.h"
+#include "v_centre.h"
+
+
+/*
+ *	centre_of_vertices
+ *	Return the coordinates of the centre of a group of vertices.
+ */
+void centre_of_vertices (SelPtr list, int *x, int *y)
+{
+SelPtr cur;
+int nitems;
+long x_sum;
+long y_sum;
+
+x_sum = 0;
+y_sum = 0;
+for (nitems = 0, cur = list; cur; cur = cur->next, nitems++)
+   {
+   x_sum += Vertices[cur->objnum].x;
+   y_sum += Vertices[cur->objnum].y;
+   }
+if (nitems == 0)
+   {
+   *x = 0;
+   *y = 0;
+   }
+else
+   {
+   *x = (int) (x_sum / nitems);
+   *y = (int) (y_sum / nitems);
+   }
+}
+
+
+/*
+ *	centre_of_vertices
+ *	Return the coordinates of the centre of a group of vertices.
+ */
+void centre_of_vertices (const bitvec_c &bv, int &x, int &y)
+{
+long x_sum = 0;
+long y_sum = 0;
+int nmax = bv.nelements ();
+int nvertices = 0;
+for (int n = 0; n < nmax; n++)
+   {
+   if (bv.get (n))
+      {
+      x_sum += Vertices[n].x;
+      y_sum += Vertices[n].y;
+      nvertices++;
+      }
+   }
+if (nvertices == 0)
+   {
+   x = 0;
+   y = 0;
+   }
+else
+   {
+   x = (int) (x_sum / nvertices);
+   y = (int) (y_sum / nvertices);
+   }
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/v_centre.h	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,10 @@
+/*
+ *	v_centre.h
+ *	AYM 1998-11-22
+ */
+
+
+void centre_of_vertices (SelPtr list, int *x, int *y);
+void centre_of_vertices (const bitvec_c &bv, int &x, int &y);
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/v_merge.cc	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,414 @@
+/*
+ *	v_merge.cc
+ *	Merging vertices
+ *	AYM 1998-02-04
+ */
+
+
+/*
+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 "dialog.h"
+#include "levels.h"
+#include "objects.h"
+#include "objid.h"
+#include "selectn.h"
+
+
+typedef struct  /* Used only by AutoMergeVertices() and SortLinedefs() */
+  {
+  int vertexl;
+  int vertexh;
+  int linedefno;
+  } linedef_t;
+
+/* Called only by AutoMergeVertices() */
+static int SortLinedefs  (const void *item1, const void *item2);
+
+
+/*
+   delete a vertex and join the two linedefs
+*/
+
+void DeleteVerticesJoinLineDefs (SelPtr obj)
+{
+int    lstart, lend, l;
+SelPtr cur;
+char   msg[80];
+
+ObjectsNeeded (OBJ_LINEDEFS, 0);
+while (obj != NULL)
+   {
+   cur = obj;
+   obj = obj->next;
+   lstart = -1;
+   lend = -1;
+   for (l = 0; l < NumLineDefs; l++)
+      {
+      if (LineDefs[l].start == cur->objnum)
+	 {
+	 if (lstart == -1)
+	    lstart = l;
+	 else
+	    lstart = -2;
+	 }
+      if (LineDefs[l].end == cur->objnum)
+	 {
+	 if (lend == -1)
+	    lend = l;
+	 else
+	    lend = -2;
+	 }
+      }
+   if (lstart < 0 || lend < 0)
+      {
+      Beep ();
+      sprintf (msg, "Cannot delete vertex #%d and join the linedefs",
+	cur->objnum);
+      Notify (-1, -1, msg, "The vertex must be the start of one linedef"
+	" and the end of another one");
+      continue;
+      }
+   LineDefs[lend].end = LineDefs[lstart].end;
+   DeleteObject (Objid (OBJ_LINEDEFS, lstart));
+   DeleteObject (Objid (OBJ_VERTICES, cur->objnum));
+   MadeChanges = 1;
+   MadeMapChanges = 1;
+   }
+}
+
+
+
+/*
+   merge several vertices into one
+*/
+
+void MergeVertices (SelPtr *list)
+{
+int    v, l;
+
+ObjectsNeeded (OBJ_LINEDEFS, 0);
+v = (*list)->objnum;
+UnSelectObject (list, v);
+if (*list == NULL)
+   {
+   Beep ();
+   Notify (-1, -1, "You must select at least two vertices", NULL);
+   return;
+   }
+/* change the linedefs starts & ends */
+for (l = 0; l < NumLineDefs; l++)
+   {
+   if (IsSelected (*list, LineDefs[l].start))
+      {
+      /* don't change a linedef that has both ends on the same spot */
+      if (!IsSelected (*list, LineDefs[l].end) && LineDefs[l].end != v)
+	 LineDefs[l].start = v;
+      }
+   else if (IsSelected (*list, LineDefs[l].end))
+      {
+      /* idem */
+      if (LineDefs[l].start != v)
+	 LineDefs[l].end = v;
+      }
+   }
+/* delete the vertices (and some linedefs too) */
+DeleteObjects (OBJ_VERTICES, list);
+MadeChanges = 1;
+MadeMapChanges = 1;
+}
+
+
+
+/*
+   check if some vertices should be merged into one
+
+   <operation> can have the following values :
+      'i' : called after insertion of new vertex
+      'm' : called after moving of vertices
+
+   Returns a non-zero value if the screen needs to be redrawn.
+*/
+
+bool AutoMergeVertices (SelPtr *list, int obj_type, char operation)
+{
+SelPtr ref, cur;
+bool   redraw;
+bool   flipped, mergedone, isldend;
+int    v, refv;
+int    ld, sd;
+int    oldnumld;
+confirm_t confirm_flag;
+
+/* FIXME this is quick-and-dirty hack ! The right thing
+   would be to :
+   - if obj_type == OBJ_THINGS, return
+   - if obj_type == OBJ_SECTORS or OBJ_LINEDEFS, select
+     all the vertices used by those sectors/linedefs and
+     proceed as usually. */
+if (obj_type != OBJ_VERTICES)
+   return false;
+
+ObjectsNeeded (OBJ_VERTICES, 0);
+redraw = false;
+mergedone = false;
+isldend = false;
+
+if (operation == 'i')
+   confirm_flag = insert_vertex_merge_vertices;
+else
+   confirm_flag = YC_ASK_ONCE;
+
+/* first, check if two (or more) vertices should be merged */
+ref = *list;
+while (ref)
+   {
+   refv = ref->objnum;
+   ref = ref->next;
+   /* check if there is a vertex at the same position (same X and Y) */
+   for (v = 0; v < NumVertices; v++)
+      if (v != refv
+         && Vertices[refv].x == Vertices[v].x
+	 && Vertices[refv].y == Vertices[v].y)
+         {
+         char buf[81];
+	 redraw = true;
+         sprintf (buf, "Vertices %d and %d occupy the same position", refv, v);
+	 if (Confirm2 (-1, -1, &confirm_flag,
+            buf,
+	    "Do you want to merge them into one?"))
+	    {
+	    /* merge the two vertices */
+	    mergedone = true;
+	    cur = NULL;
+	    SelectObject (&cur, refv);
+	    SelectObject (&cur, v);
+	    MergeVertices (&cur);
+	    /* not useful but safer... */
+	    ObjectsNeeded (OBJ_VERTICES, 0);
+	    /* update the references in the selection list */
+	    for (cur = *list; cur; cur = cur->next)
+	       if (cur->objnum > refv)
+		  cur->objnum = cur->objnum - 1;
+	    if (v > refv)
+	       v--;
+	    /* the old vertex has been deleted */
+	    UnSelectObject (list, refv);
+	    /* select the new vertex instead */
+	    if (!IsSelected (*list, v))
+	       SelectObject (list, v);
+	    break;
+	    }
+	 else
+	    return redraw;
+         }
+   }
+
+/* Now, check if one or more vertices are on a linedef */
+//DisplayMessage  (-1, -1, "Checking vertices on a linedef");
+
+// Distance in map units that is equivalent to 4 pixels
+int tolerance = (int) (4 / Scale);
+
+if (operation == 'i')
+   confirm_flag = insert_vertex_split_linedef;
+else
+   confirm_flag = YC_ASK_ONCE;
+ref = *list;
+while (ref)
+   {
+   refv = ref->objnum;
+   ref = ref->next;
+   oldnumld = NumLineDefs;
+   //printf ("V%d %d\n", refv, NumLineDefs); // DEBUG;
+   /* check if this vertex is on a linedef */
+   for (ld = 0; ld < oldnumld; ld++)
+      {
+      ObjectsNeeded (OBJ_VERTICES, OBJ_LINEDEFS, 0);
+      if (LineDefs[ld].start == refv || LineDefs[ld].end == refv)
+         {
+	 /* one vertex had a linedef bound to it -- check it later */
+	 isldend = true;
+         }
+      else if (IsLineDefInside (ld, Vertices[refv].x - tolerance,
+				    Vertices[refv].y - tolerance, 
+				    Vertices[refv].x + tolerance,
+				    Vertices[refv].y + tolerance))
+         {
+         char buf[81];
+	 redraw = true;
+         sprintf (buf, "Vertex %d is on top of linedef %d", refv, ld);
+	 if (Confirm2 (-1, -1, &confirm_flag,
+            buf,
+            "Do you want to split the linedef there?"))
+	    {
+	    /* split the linedef */
+	    mergedone = true;
+	    InsertObject (OBJ_LINEDEFS, ld, 0, 0);
+	    LineDefs[ld].end = refv;
+	    LineDefs[NumLineDefs - 1].start = refv;
+	    sd = LineDefs[ld].sidedef1;
+	    if (sd >= 0)
+	       {
+	       InsertObject (OBJ_SIDEDEFS, sd, 0, 0);
+	       ObjectsNeeded (OBJ_LINEDEFS, 0);
+	       LineDefs[NumLineDefs - 1].sidedef1 = NumSideDefs - 1;
+	       }
+ 	    sd = LineDefs[ld].sidedef2;
+	    if (sd >= 0)
+	       {
+	       InsertObject (OBJ_SIDEDEFS, sd, 0, 0);
+	       ObjectsNeeded (OBJ_LINEDEFS, 0);
+	       LineDefs[NumLineDefs - 1].sidedef2 = NumSideDefs - 1;
+	       }
+	    MadeChanges = 1;
+	    MadeMapChanges = 1;
+	    }
+	 else
+	    return redraw;
+         }
+      }
+   }
+
+/* Don't continue if this isn't necessary */
+if (! isldend || ! mergedone)
+   return redraw;
+
+/* finally, test if two linedefs are between the same pair of vertices */
+/* AYM 1997-07-17
+   Here I put a new algorithm. The original one led to a very large
+   number of tests (N*(N-1)/2 where N is number of linedefs). For
+   example, for a modest sized level (E1M4, 861 linedefs), it made
+   about 350,000 tests which, on my DX4/75, took about 3 seconds.
+   That IS irritating.
+   The new algorithm makes about N*log(N)+N tests, which is, in the
+   same example as above, about 3,400 tests. That's about 100 times
+   less. To be rigorous, it is not really 100 times faster because the
+   N*log(N) operations are function calls from within qsort() that
+   must take longer than inline tests. Anyway, the checking is now
+   almost instantaneous and that's what I wanted.
+   The principle is to sort the linedefs by smallest numbered vertex
+   then highest numbered vertex. Thus, two overlapping linedefs must
+   be neighbours in the array. No need to test the N-2 others like
+   before. */
+
+//DisplayMessage (-1, -1, "Checking superimposed linedefs");
+confirm_flag = YC_ASK_ONCE;
+{
+linedef_t *linedefs;
+
+/* Copy the linedefs into array 'linedefs' and sort it */
+linedefs = (linedef_t *) GetMemory (NumLineDefs * sizeof (linedef_t));
+for (ld = 0; ld < NumLineDefs; ld++)
+  {
+  linedefs[ld].vertexl = y_min (LineDefs[ld].start, LineDefs[ld].end);
+  linedefs[ld].vertexh = y_max (LineDefs[ld].start, LineDefs[ld].end);
+  linedefs[ld].linedefno = ld;
+  }
+qsort (linedefs, NumLineDefs, sizeof (linedef_t), SortLinedefs);
+
+/* Search for superimposed linedefs in the array */
+for (ld = 0; ld+1 < NumLineDefs; ld++)
+   {
+   if (linedefs[ld+1].vertexl != linedefs[ld].vertexl
+    || linedefs[ld+1].vertexh != linedefs[ld].vertexh)
+     continue;
+   int ld1 = linedefs[ld].linedefno;
+   int ld2 = linedefs[ld+1].linedefno;
+   char prompt[81];
+   y_snprintf (prompt, sizeof prompt, "Linedefs %d and %d are superimposed",
+      ld1, ld2);
+   redraw = true;
+   if (Expert || Confirm2 (-1, -1, &confirm_flag,
+      prompt, "(and perhaps others too). Merge them ?"))
+      {
+      LDPtr ldo = LineDefs + ld1;
+      LDPtr ldn = LineDefs + ld2;
+      /* Test if the linedefs have the same orientation */
+      if (ldn->start == ldo->end)
+	 flipped = true;
+      else
+	 flipped = false;
+      /* Merge linedef ldo (ld) into linedef ldn (ld+1) */
+      /* FIXME When is this done ? Most of the time when adding a
+	 door/corridor/window between two rooms, right ? So we should
+	 handle this in a smarter way by copying middle texture into
+	 lower and upper texture if the sectors don't have the same
+	 heights and maybe setting the LTU and UTU flags.
+	 This also applies when a linedef becomes two-sided as a
+	 result of creating a new sector. */
+      if (ldn->sidedef1 < 0)
+	 {
+	 if (flipped)
+	    {
+	    ldn->sidedef1 = ldo->sidedef2;
+	    ldo->sidedef2 = OBJ_NO_NONE;
+	    }
+	 else
+	    {
+	    ldn->sidedef1 = ldo->sidedef1;
+	    ldo->sidedef1 = OBJ_NO_NONE;
+	    }
+	 }
+      if (ldn->sidedef2 < 0)
+         {
+	 if (flipped)
+	    {
+	    ldn->sidedef2 = ldo->sidedef1;
+	    ldo->sidedef1 = OBJ_NO_NONE;
+	    }
+	 else
+	    {
+	    ldn->sidedef2 = ldo->sidedef2;
+	    ldo->sidedef2 = OBJ_NO_NONE;
+	    }
+         }
+      if (ldn->sidedef1 >= 0 && ldn->sidedef2 >= 0 && (ldn->flags & 0x04) == 0)
+	 ldn->flags = 0x04;
+      DeleteObject (Objid (OBJ_LINEDEFS, ld1));
+      }
+   }
+
+FreeMemory (linedefs);
+}
+
+return redraw;
+}
+
+
+/*
+   compare two linedefs for sorting by lowest numbered vertex
+*/
+static int SortLinedefs (const void *item1, const void *item2)
+{
+#define ld1 ((const linedef_t *) item1)
+#define ld2 ((const linedef_t *) item2)
+if (ld1->vertexl != ld2->vertexl)
+  return ld1->vertexl - ld2->vertexl;
+if (ld1->vertexh != ld2->vertexh)
+  return ld1->vertexh - ld2->vertexh;
+return 0;
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/v_polyg.cc	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,54 @@
+/*
+ *	v_polyg.cc
+ *	AYM 1998-08-15
+ */
+
+
+/*
+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 "objects.h"
+#include "objid.h"
+#include <math.h>
+
+
+/*
+   insert the vertices of a new polygon
+*/
+
+void InsertPolygonVertices (int centerx, int centery, int sides, int radius)
+{
+int n;
+
+for (n = 0; n < sides; n++)
+  InsertObject (OBJ_VERTICES, -1,
+    centerx
+    + (int) ((double)radius * cos (TWOPI * (double)n / (double)sides)),
+    centery
+    + (int) ((double)radius * sin (TWOPI * (double)n / (double)sides)));
+}
+
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/vectext.cc	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,282 @@
+/*
+ *	vectext.cc - crude scalable text
+ *	AYM 2000-07-11
+ */
+
+
+/*
+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 <X11/Xlib.h>
+#include "gfx.h"
+#include "vectext.h"
+
+
+static const signed char vmin[] =
+{
+  16, 
+  'M',   0,  20, 
+  'd',  16,   0, 
+};
+
+static const signed char v0[] =
+{
+  24, 
+  'M',   8,   0, 
+  'd',   8,   0, 
+  'd',   8,  12, 
+  'd',   0,  24, 
+  'd',  -8,  12, 
+  'd',  -8,   0, 
+  'd',  -8, -12, 
+  'd',   0, -24, 
+  'd',   8, -12, 
+};
+
+static const signed char v1[] =
+{
+  12, 
+  'M',   0,   8, 
+  'd',   8,  -8, 
+  'd',   0,  49, 
+};
+
+static const signed char v2[] =
+{
+  26, 
+  'M',   0,   4, 
+  'd',   8,  -4, 
+  'd',   8,   0, 
+  'd',   8,   8, 
+  'd',   0,   8, 
+  'd', -24,  32, 
+  'd',  26,   0, 
+};
+
+static const signed char v3[] =
+{
+  24, 
+  'M',   0,   4, 
+  'd',   8,  -4, 
+  'd',   8,   0, 
+  'd',   8,   8, 
+  'd',   0,   8, 
+  'd',  -8,   8,
+  'm',  -8,   0, 
+  'd',   8,   0, 
+  'd',   8,   8, 
+  'd',   0,   8, 
+  'd',  -8,   8, 
+  'd',  -8,   0, 
+  'd',  -8,  -4, 
+};
+
+static const signed char v4[] =
+{
+  24, 
+  'M',  24,  32, 
+  'd', -24,   0, 
+  'd',  20, -32, 
+  'd',   0,  48, 
+};
+
+static const signed char v5[] =
+{
+  28, 
+  'M',  28,   0, 
+  'd', -24,   0, 
+  'd',  -4,  20, 
+  'd',  20,   0, 
+  'd',   8,   8, 
+  'd',   0,  12, 
+  'd',  -8,   8, 
+  'd', -12,   0, 
+  'd',  -8,  -4, 
+};
+
+static const signed char v6[] =
+{
+  28, 
+  'M',  24,   0, 
+  'd', -16,   0, 
+  'd',  -8,  12, 
+  'd',   0,  24, 
+  'd',   8,  12, 
+  'd',  12,   0, 
+  'd',   8,  -8, 
+  'd',   0,  -8, 
+  'd',  -8,  -8, 
+  'd', -20,   0, 
+};
+
+static const signed char v7[] =
+{
+  24, 
+  'M',   0,   0, 
+  'd',  24,   0, 
+  'd', -20,  49, 
+};
+
+static const signed char v8[] =
+{
+  28, 
+  'M',   8,  24, 
+  'd',  -8,  -6, 
+  'd',   0, -12, 
+  'd',   8,  -6, 
+  'd',  12,   0, 
+  'd',   8,   6, 
+  'd',   0,  12, 
+  'd',  -8,   6, 
+  'd', -12,   0, 
+  'd',  -8,   6,
+  'd',   0,  12, 
+  'd',   8,   6, 
+  'd',  12,   0, 
+  'd',   8,  -6, 
+  'd',   0, -12, 
+  'd',  -8,  -6, 
+};
+
+static const signed char v9[] =
+{
+  28, 
+  'M',  28,  24, 
+  'd', -20,   0, 
+  'd',  -8,  -8, 
+  'd',   0,  -8, 
+  'd',   8,  -8, 
+  'd',  12,   0, 
+  'd',   8,  12, 
+  'd',   0,  24, 
+  'd',  -8,  12, 
+  'd', -16,   0, 
+};
+
+
+
+static inline void vdata (char c, const signed char *& p, size_t& s)
+{
+  switch (c)
+  {
+    case '-': p = vmin; s = sizeof vmin; break;
+    case '0': p = v0;   s = sizeof v0;   break;
+    case '1': p = v1;   s = sizeof v1;   break;
+    case '2': p = v2;   s = sizeof v2;   break;
+    case '3': p = v3;   s = sizeof v3;   break;
+    case '4': p = v4;   s = sizeof v4;   break;
+    case '5': p = v5;   s = sizeof v5;   break;
+    case '6': p = v6;   s = sizeof v6;   break;
+    case '7': p = v7;   s = sizeof v7;   break;
+    case '8': p = v8;   s = sizeof v8;   break;
+    case '9': p = v9;   s = sizeof v9;   break;
+    default:  p = 0;    s = 0;           break;
+  }
+}
+
+
+static inline int vwidth (char c)
+{
+  const signed char *d;
+  size_t s;
+  vdata (c, d, s);
+  if (d == 0)
+    return 0;
+  return *d;
+}
+
+
+void draw_vint (int number, int x, int y, double scale)
+{
+  char buf[20];
+  y_snprintf (buf, sizeof buf, "%d", number);
+  draw_vstring (buf, x, y, scale);
+}
+
+
+void draw_vstring (const char *string, int x, int y, double scale)
+{
+  const int    height = 48;		// Height in units FIXME hard-coded
+  const double ppu    = scale / 4;	// Pixels per unit
+
+  // Calculate in advance the whole width of the text
+  int width = 0;			// Width in units
+  for (const char *s = string; *s; s++)
+    width += vwidth (*s);
+  
+  int xref = (int) (x - width  * ppu / 2);
+  int yref = (int) (y - height * ppu / 2);
+  for (const char *s = string; *s; s++)
+  {
+    int xcur = xref;
+    int ycur = yref;
+    const signed char *d, *dend;
+    size_t size;
+    vdata (*s, d, size);
+    if (d == 0 || size < 1)
+      continue;
+    dend = d + size;
+
+    // Extract the width;
+    int w = *d++;
+
+    // Process the statements
+    while ((d + 2) < dend)
+    {
+      if (*d == 'd')  // d - draw to relative position
+      {
+	d++;
+	int xofs = *d++;
+	int yofs = *d++;
+	DrawScreenLine (
+	   (int) (xref + xcur          * ppu + 0.5),
+	   (int) (yref + ycur          * ppu + 0.5),
+	   (int) (xref + (xcur + xofs) * ppu + 0.5),
+	   (int) (yref + (ycur + yofs) * ppu + 0.5));
+	xcur += xofs;
+	ycur += yofs;
+      }
+      else if (*d == 'm')  // m - move the cursor to relative position
+      {
+	d++;
+	xcur += *d++;
+	ycur += *d++;
+      }
+      else if (*d == 'M')  // M - move the cursor to absolute position
+      {
+	d++;
+	xcur = *d++;
+	ycur = *d++;
+      }
+      else
+      {
+	nf_bug ("bad statement \"%c\"", *d);
+	d += 3;
+	continue;
+      }
+    }
+    xref += (int) ((w + 8) * ppu + 0.5);
+  }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/vectext.h	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,9 @@
+/*
+ *	vectext.h - crude scalable text
+ *	AYM 2000-07-11
+ */
+
+
+void draw_vint    (int         number, int x, int y, double scale);
+void draw_vstring (const char *string, int x, int y, double scale);
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/verbmsg.cc	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,47 @@
+/*
+ *	verbmsg.cc
+ *	AYM 1998-11-11
+ */
+
+
+/*
+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"
+
+
+/*
+ *	verbmsg
+ *	Like printf() but does nothing unlike <verbose> is set.
+ */
+void verbmsg (const char *fmt, ...)
+{
+va_list args;
+
+if (! verbose)
+   return;
+va_start (args, fmt);
+vprintf (fmt, args);
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/version.cc	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,4 @@
+// DO NOT EDIT -- generated from VERSION
+
+extern const char *const yadex_source_date = "2003-12-28";
+extern const char *const yadex_version = "1.7.0";
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/wadfile.cc	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,125 @@
+/*
+ *	wadfile.cc - Wad_file class
+ *	AYM 2001-09-18
+ */
+
+
+/*
+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.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 "wadfile.h"
+
+
+/*
+ *	Wad_file::~Wad_file - dtor
+ */
+Wad_file::~Wad_file ()
+{
+  if (directory != 0)
+  {
+    FreeMemory (directory);
+    directory = 0;			// Catch bugs
+  }
+  if (fp != 0)
+  {
+    fclose (fp);
+    fp = 0;				// Catch bugs
+  }
+  if (filename != 0)
+  {
+    FreeMemory (filename);
+    filename = 0;			// Catch bugs
+  }
+}
+
+
+/*
+ *	Wad_file::where - return file(offset) string
+ *
+ *	Return pointer to a per-Wad_file buffer.
+ */
+const char *Wad_file::where () const
+{
+  const unsigned long offset       = ftell (fp);
+  const size_t        offset_len   =  + 3;
+  const size_t        name_len_max = sizeof where_ - 1 - offset_len;
+
+  if (name_len_max >= strlen (filename)) 
+    sprintf (where_, "%s(%lXh)", filename, offset);
+  else
+  {
+    const char  *ellipsis = "...";
+    const size_t total    = name_len_max - strlen (ellipsis);
+    const size_t left     = total / 2;
+    const size_t right    = total - left;
+    sprintf (where_, "%*s%s%*s(%lXh)",
+	left, filename,
+	ellipsis,
+	right, filename + total,
+	offset);
+  }
+
+  return where_;
+}
+
+
+/*
+ *	Wad_file::read_vbytes - read bytes from a wad file
+ *
+ *	Read up to <count> bytes and store them into buffer
+ *	<buf>. <count> is _not_ limited to size_t. If an I/O
+ *	error occurs, set the error flag. EOF is not considered
+ *	an error.
+ *
+ *	Return the number of bytes read.
+ */
+long Wad_file::read_vbytes (void *buf, long count) const
+{
+  long bytes_read_total;
+  size_t bytes_read;
+  size_t bytes_to_read;
+
+  bytes_read_total = 0;
+  bytes_to_read    = 0x8000;
+  while (count > 0)
+  {
+    if (count <= 0x8000)
+      bytes_to_read = (size_t) count;
+    bytes_read = fread (buf, 1, bytes_to_read, fp);
+    bytes_read_total += bytes_read;
+    if (bytes_read != bytes_to_read)
+      break;
+    buf = (char *) buf + bytes_read;
+    count -= bytes_read;
+  }
+  if (ferror (fp))
+  {
+    if (! error_)
+      err ("%s: read error", where ());
+    error_ = true;
+  }
+  return bytes_read_total;
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/wadfile.h	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,349 @@
+/*
+ *	wadfile.h - Wad_file class
+ *	AYM 2001-09-18
+ */
+
+
+/*
+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.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.
+*/
+
+
+#ifndef YH_WADFILE  /* DO NOT INSERT ANYTHING BEFORE THIS LINE */
+#define YH_WADFILE
+
+
+/*
+ *	Wad_file - wad file open for reading
+ *
+ *	The Wad_file class is a simple wad file object. It
+ *	provides functions to read the usual data formats (byte,
+ *	16-bit signed integer, 32-bit signed integer) portably.
+ *
+ *	Errors are reported not by overloading the return
+ *	value but by setting an internal flag that can be read
+ *	with the error() function, a bit like stdio's feof() and
+ *	ferror(). Calling error() has the side effect of
+ *	clearing the error flag and calling clearerr() on the
+ *	underlying FILE. This is the only way to reset the error
+ *	flag. Thus, you don't have to check the error status
+ *	after every operation. You can call seek() and read_*()
+ *	any number of times before calling error() : the class
+ *	guarantees that if any one of the operations failed,
+ *	error() returns true.
+ *
+ *	Yadex has a policy of reporting I/O errors, mentioning
+ *	the name of the file and the offset at which the error
+ *	occurred. This policy is enforced by the Wad_file class.
+ *	To avoid flooding, no message is printed if the error
+ *	flag was already set before the error occurred. This
+ *	gives you some control on how verbose the error
+ *	reporting is ; if you want a message for every error,
+ *	all you have to do is to check error() after every
+ *	operation. It's probably best to report only the first
+ *	error, though.
+ *
+ *	If for some reason you need to disable the error
+ *	messages, add a bool quiet parameter with a default
+ *	value of false to the functions that can fail.
+ *
+ *	It's probably a good idea to call error() after every
+ *	seek(), before attempting to read. Although seek()
+ *	rarely fails under Unix, MS-DOS refuses to seek() past
+ *	EOF, if I recall correctly.
+ *
+ *	The interface is somewhat crufty. Some functions take a
+ *	pointer, others take a reference. Some take an optional
+ *	count parameter, some take a mandatory count parameter,
+ *	and some have no count parameter at all. Needs cleanup.
+ *
+ *	This class has many public data members, and no proper
+ *	constructor. That's because it evolved from a C struct.
+ *
+ *	Another problem is the lack of errno detail. That is
+ *	partly stdio's fault.
+ *
+ *	const: for the moment, const means that you can read
+ *	from but not change the attributes, close, reopen, etc.
+ */
+class Wad_file
+{
+  /* Ugly but better than making the data members public. FIXME
+     Many of these are friend just because they use fp for
+     reading. */
+  friend char     *GetWadFileName     (const char *);
+  friend int       SaveLevelData      (const char *, const char *);
+  friend int       OpenMainWad        (const char *);
+  friend int       OpenPatchWad       (const char *);
+  friend Wad_file *BasicWadOpen       (const char *, ygpf_t);
+  friend void      BuildNewMainWad    (const char *, bool);
+  friend void      SaveDirectoryEntry (FILE *, const char *);
+  friend void      SaveEntryToRawFile (FILE *, const char *);
+  friend void      ListFileDirectory  (FILE *, const Wad_file *);
+
+  public :
+    Wad_file () :
+      filename (0),
+      pic_format_ (YGPF_NORMAL),
+      fp (0),
+      dirsize (0),
+      dirstart (0),
+      directory (0),
+      error_ (false)
+    {
+      strcpy (type, "BUG");
+      strcpy (where_, "DEADBEEF");
+    }
+    ~Wad_file ();
+    const char *pathname    () const;
+    ygpf_t      pic_format  () const;
+    bool        error       () const;
+    const char *where       () const;
+    void        seek        (long offset) const;
+    u8          read_u8     () const;
+    void        read_u8     (u8& buf) const;
+    i16         read_i16    () const;
+    void        read_i16    (i16 *buf) const;
+    void        read_i32    (i32 *buf, long count = 1) const;
+    void        read_bytes  (void *buf, long count) const;
+    long        read_vbytes (void *buf, long count) const;
+    const char *what        () const;
+
+  private :
+    char *filename;			// Name of the wad file
+    ygpf_t pic_format_;			// Picture format (usually PF_NORMAL)
+    FILE *fp;				// C file stream information
+    char type[4];			// Type of wad file ("IWAD" or "PWAD")
+    i32  dirsize;			// Entries in directory
+    i32  dirstart;			// Offset to start of directory
+    DirPtr directory;			// Array of directory information
+    mutable bool error_;		// I/O error occur since last error()
+    mutable char where_[101];		// Static workspace for where()
+
+    Wad_file (const Wad_file& rhs);		// Deliberately not implemented
+    Wad_file& operator= (const Wad_file& rhs);	// Deliberately not implemented
+};
+
+
+/*
+ *	Wad_file::pathname - return the pathname of the file
+ */
+inline const char *Wad_file::pathname () const
+{
+  return filename;
+}
+
+
+/*
+ *	Wad_file::pic_format - return the pic_format of the wad
+ */
+inline ygpf_t Wad_file::pic_format () const
+{
+  return pic_format_;
+}
+
+
+/*
+ *	Wad_file::error - tell whether any errors occurred
+ *
+ *	Reset the error indicator and call clearerr() on the
+ *	underlying stdio stream. Thus calling Wad_file::error()
+ *	again immediately after always returns false. Calling
+ *	this function is the only way to clear the error flag of
+ *	a Wad_file.
+ *
+ *	So short that it's a good candidate for inlining.
+ *
+ *	Return true if an error occurred, false otherwise.
+ */
+inline bool Wad_file::error () const
+{
+  if (! error_)
+    return false;
+
+  clearerr (fp);
+  error_ = false;
+  return true;
+}
+
+
+/*
+ *	Wad_file::seek - move the file pointer
+ *
+ *	If an error occurs, set the error flag.
+ */
+inline void Wad_file::seek (long offset) const
+{
+  if (fseek (fp, offset, 0) != 0)
+  {
+    if (! error_)
+      err ("%s: can't seek to %lXh", filename, offset);
+    error_ = true;
+  }
+}
+
+
+/*
+ *	Wad_file::read_u8 - read a byte
+ *
+ *	If an error occurs, set the error flag and the return
+ *	value is undefined.
+ */
+inline u8 Wad_file::read_u8 () const
+{
+  u8 v = u8 (getc (fp));
+
+  if (feof (fp) || ferror (fp))
+  {
+    if (! error_)
+      err ("%s: read error", where ());
+    error_ = true;
+  }
+  return v;
+}
+
+
+/*
+ *	Wad_file::read_u8 - read a byte
+ *
+ *	If an error occurs, set the error flag and the contents
+ *	of buf is undefined.
+ */
+inline void Wad_file::read_u8 (u8& buf) const
+{
+  buf = getc (fp);
+
+  if (feof (fp) || ferror (fp))
+  {
+    if (! error_)
+      err ("%s: read error", where ());
+    error_ = true;
+  }
+}
+
+
+/*
+ *	Wad_file::read_i16 - read a little-endian 16-bit signed integer
+ *
+ *	If an error occurs, set the error flag and the return
+ *	value is undefined.
+ */
+inline i16 Wad_file::read_i16 () const
+{
+  const size_t nbytes = 2;
+  u8 buf[nbytes];
+
+  if (fread (buf, 1, nbytes, fp) != nbytes)
+  {
+    if (! error_)
+      err ("%s: read error", where ());
+    error_ = true;
+    return EOF;  // Whatever
+  }
+  return buf[0] | buf[1] << 8;
+}
+
+
+/*
+ *	Wad_file::read_i16 - read a little-endian 16-bit signed integer
+ *
+ *	The value read is stored in *buf. If an error occurs,
+ *	set the error flag and the contents of *buf is undefined.
+ */
+inline void Wad_file::read_i16 (i16 *buf) const
+{
+  *buf = getc (fp) | (getc (fp) << 8);
+
+  if (feof (fp) || ferror (fp))
+  {
+    if (! error_)
+      err ("%s: read error", where ());
+    error_ = true;
+  }
+}
+
+
+/*
+ *	Wad_file::read_i32 - read little-endian 32-bit signed integers
+ *
+ *	Read <count> little-endian 32-bit signed integers from
+ *	wad file <wadfile> into *buf. If an error occurs, set
+ *	error_ and the contents of *buf is undefined.
+ */
+inline void Wad_file::read_i32 (i32 *buf, long count) const
+{
+  while (count-- > 0)
+  {
+    *buf++ =    getc (fp)
+       | (      getc (fp) << 8)
+       | ((i32) getc (fp) << 16)
+       | ((i32) getc (fp) << 24);
+  }
+
+  if (feof (fp) || ferror (fp))
+  {
+    if (! error_)
+      err ("%s: read error", where ());
+    error_ = true;
+  }
+}
+
+
+/*
+ *	Wad_file::read_bytes - read bytes from a wad file
+ *
+ *	Read <count> bytes and store them into buffer <buf>.
+ *	<count> is _not_ limited to size_t. If an I/O error
+ *	occurs or EOF is reached before the requested number of
+ *	bytes is read, set the error flag.
+ */
+inline void Wad_file::read_bytes (void *buf, long count) const
+{
+  long bytes_read;
+
+  bytes_read = read_vbytes (buf, count);
+  if (bytes_read != count)
+  {
+    if (! error_)
+      err ("%s: read error", where ());
+    error_ = true;
+  }
+}
+
+
+/*
+ *	Wad_file::what - what a wad contains
+ *
+ *	Written for the sake of the "w" command. Return the
+ *	name of the first lump in the wad, which gives an idea
+ *	of what it contains. The string is *not* NUL-terminated.
+ */
+inline const char *Wad_file::what () const
+{
+  if (directory == 0)
+    return "(nodir)";
+  if (dirsize < 1)
+    return "(empty)";
+  return directory[0].name;
+}
+
+
+#endif  /* DO NOT ADD ANYTHING AFTER THIS LINE */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/wadlist.cc	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,182 @@
+/*
+ *	wadlist.cc - Wad_list class
+ *	AYM 2001-09-23
+ */
+
+
+/*
+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.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 "wadfile.h"
+#include "wadlist.h"
+#include <list>
+#include <boost/smart_ptr.hpp>
+
+
+Wad_list wad_list;			// One global instance
+
+
+typedef std::list<boost::shared_ptr<Wad_file> > list_t;
+
+
+class Wad_list_priv
+{
+  public :
+    Wad_list_priv ();
+    list_t list;
+    mutable list_t::iterator iter;	// Current element
+    mutable bool rewound;		// If true, next get() will return head
+};
+
+
+Wad_list_priv::Wad_list_priv ()
+{
+  rewound = true;
+}
+
+
+/*
+ *	Wad_list::Wad_list - default ctor
+ */
+Wad_list::Wad_list ()
+{
+  priv = new Wad_list_priv;
+}
+
+
+/*
+ *	Wad_list::~Wad_list - dtor
+ */
+Wad_list::~Wad_list ()
+{
+  delete priv;
+  priv = 0;				// Catch bugs
+}
+
+
+/*
+ *	Wad_list::rewind - arrange so that the next get() will return head
+ */
+void Wad_list::rewind () const
+{
+  priv->rewound = true;
+}
+
+
+/*
+ *	Wad_list::get - retrieve the next wad from the list
+ *
+ *	If get() was not called since the last call to rewind(),
+ *	the first wad is returned. Otherwise, the wad returned
+ *	is the one that follows the one returned by the previous
+ *	call to get().
+ *
+ *	Return false if already at the end of the list, true
+ *	otherwise.
+ */
+bool Wad_list::get (Wad_file *& wf)
+{
+  if (priv->rewound)
+  {
+    priv->iter = priv->list.begin ();
+    priv->rewound = false;
+  }
+  else
+    ++priv->iter;
+
+  if (priv->iter == priv->list.end ())
+  {
+    wf = 0;
+    return false;
+  }
+
+  wf = priv->iter->get ();
+  return true;
+}
+
+
+bool Wad_list::get (const Wad_file *& wf) const
+{
+  if (priv->rewound)
+  {
+    priv->iter = priv->list.begin ();
+    priv->rewound = false;
+  }
+  else
+    ++priv->iter;
+
+  if (priv->iter == priv->list.end ())
+    return false;
+
+  wf = priv->iter->get ();
+  return true;
+}
+
+
+/*
+ *	Wad_list::insert - insert a new wad at the pointer
+ */
+void Wad_list::insert (Wad_file *wf)
+{
+  priv->list.insert (priv->iter, boost::shared_ptr<Wad_file> (wf));
+}
+
+
+/*
+ *	Wad_list::del - delete from the list the wad under the pointer
+ *
+ *	If get() was not called since the last call to rewind(),
+ *	the first wad is deleted. Otherwise, the wad deleted is
+ *	the one returned by the last call to get().
+ *
+ *	After a call to del(), a call to get will return the wad
+ *	the followed the one that was deleted.
+ *
+ *	If already at the end of the list, nf_bug() is called.
+ */
+void Wad_list::del ()
+{
+  list_t::iterator i;
+
+  if (priv->rewound)
+  {
+    i = priv->list.begin ();
+  }
+  else
+  {
+    i = priv->iter;
+  }
+  if (i == priv->list.end ())
+  {
+    nf_bug ("Wad_list::del: attempt to delete last item");
+    return;
+  }
+  priv->iter = priv->list.erase (i);
+  if (priv->iter == priv->list.begin ())
+  {
+    priv->iter = 0;			// Catch bugs
+    priv->rewound = true;
+  }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/wadlist.h	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,83 @@
+/*
+ *	wadlist.h - Wad_list class
+ *	AYM 2001-09-23
+ */
+
+
+/*
+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.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.
+*/
+
+
+#ifndef YH_WADLIST  /* DO NOT INSERT ANYTHING BEFORE THIS LINE */
+#define YH_WADLIST
+
+
+/*
+ *	Wad_list - list of open wads
+ *
+ *	The Wad_list class is designed to hold the list of open
+ *	wads. It will probably have only one (global) instance.
+ *	Here is how it's supposed to be used :
+ *
+ *	  extern Wad_list wl;
+ *	  Wad_file *wf;
+ *
+ *	  // Is foo.wad in our list ?
+ *	  for (wl.rewind (); wl.get (wf);)
+ *	    if (strcmp (wf->filename, "foo.wad") == 0)
+ *	    {
+ *	      puts ("Got it !");
+ *	      break;
+ *	    }
+ *
+ *	  // Remove from the list all wads beginning with a "z"
+ *	  for (wl.rewind (); wl.get (wf);)
+ *	    if (*wf->filename == 'z')
+ *	      wl.del ();
+ */
+
+
+class Wad_list_priv;
+
+
+class Wad_list
+{
+  public :
+    Wad_list    ();
+    ~Wad_list   ();
+    void rewind () const;
+    bool get    (const Wad_file *& wf) const;
+    bool get    (Wad_file *& wf);
+    void insert (Wad_file *);
+    void del    ();
+
+  private :
+    Wad_list (const Wad_list&);			// Too lazy to implement it
+    Wad_list& operator= (const Wad_list&);	// Too lazy to implement it
+    Wad_list_priv *priv;
+};
+
+
+extern Wad_list wad_list;		// One global instance
+
+
+#endif  /* DO NOT ADD ANYTHING AFTER THIS LINE */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/wadname.h	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,166 @@
+/*
+ *	wadname.h
+ *	AYM 2000-04-13
+ */
+
+
+/*
+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.
+*/
+
+
+#ifndef YH_WADNAME
+#define YH_WADNAME
+
+
+#include <memory.h>
+#include <ctype.h>
+
+#include "wstructs.h"
+
+
+/*
+ *	Wad_name - the name of a wad directory entry
+ *  
+ *	This class is used to store a wad directory entry name.
+ *	It provides the following guarantees :
+ *
+ *	- there is minimal memory overhead,
+ *
+ *	- the name is stored in CAPITALS and padded to the
+ *	  maximum length with NULs so that the comparison of two
+ *	  names can be done with memcmp() instead of
+ *	  y_strnicmp(). This is very important for performance
+ *	  reasons.
+ */
+struct Wad_name
+{
+  inline Wad_name ();
+  inline Wad_name (const Wad_name& source);
+  inline Wad_name (const char *source);
+  inline Wad_name& operator=  (const char *source);
+  inline bool      operator== (const Wad_name& ref) const;
+  inline bool      operator== (const char *ref) const;
+  inline bool      less       (const Wad_name& other) const;
+  inline bool      has_prefix (const Wad_name& prefix) const;
+  wad_name_t name;
+};
+
+
+/*
+ *	default ctor
+ */
+inline Wad_name::Wad_name ()
+{
+  memset (name, '\0', sizeof name);
+}
+
+
+/*
+ *	initialize from a trusted source
+ *
+ *	The source *must* be already upper-cased and padded with
+ *	NULs.
+ */
+
+inline Wad_name::Wad_name (const Wad_name& source)
+{
+  memcpy (name, source.name, sizeof name);
+}
+
+
+/*
+ *	initialize from an untrusted source
+ */
+inline Wad_name::Wad_name (const char *source)
+{
+  char *p;
+  char *const pmax = name + sizeof name;
+  for (p = name; *source != '\0' && p < pmax; p++)
+    *p = toupper (*source++);
+  // Pad with NULs to the end
+  for (; p < pmax; p++)
+    *p = '\0';
+}
+
+
+/*
+ *	initialize from an untrusted source
+ */
+inline Wad_name& Wad_name::operator= (const char *source)
+{
+  char *p;
+  char *const pmax = name + sizeof name;
+  for (p = name; *source != '\0' && p < pmax; p++)
+    *p = toupper (*source++);
+  // Pad with NULs to the end
+  for (; p < pmax; p++)
+    *p = '\0';
+  return *this;
+}
+
+
+/*
+ *	compare two Wad_name objects for equality
+ */
+inline bool Wad_name::operator== (const Wad_name& ref) const
+{
+  return this == &ref || ! memcmp (name, ref.name, sizeof name);
+}
+
+
+/*
+ *	compare for equality with an untrusted char[8]
+ */
+inline bool Wad_name::operator== (const char *ref) const
+{
+  return ! y_strnicmp (name, ref, sizeof name);
+}
+
+
+/*
+ *	less - less operator for map
+ *
+ *	This is the operator suitable for use in a map. See
+ *	Lump_dir for an example.
+ *
+ *	Return true iff <this> is "smaller" (lexicographically
+ *	speaking) than <other>, false otherwise.
+ */
+inline bool Wad_name::less (const Wad_name& other) const
+{
+  const char *p1 = name;
+  const char *p2 = other.name;
+  if (*p1 < *p2) return true; if (*p1++ > *p2++) return false;
+  if (*p1 < *p2) return true; if (*p1++ > *p2++) return false;
+  if (*p1 < *p2) return true; if (*p1++ > *p2++) return false;
+  if (*p1 < *p2) return true; if (*p1++ > *p2++) return false;
+  if (*p1 < *p2) return true; if (*p1++ > *p2++) return false;
+  if (*p1 < *p2) return true; if (*p1++ > *p2++) return false;
+  if (*p1 < *p2) return true; if (*p1++ > *p2++) return false;
+  if (*p1 < *p2) return true;
+  return false;
+  // Supposedly slower
+  //return memcmp (name, other.name, sizeof name) < 0;
+}
+
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/wadnamec.cc	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,59 @@
+/*
+ *	wadnamec.cc
+ *	AYM 2000-04-11
+ */
+
+
+/*
+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 "wadnamec.h"
+
+
+Wad_name_c::Wad_name_c (const char *string)
+{
+  char *p = name;
+  char *pmax = name + 8;
+  while (*string && p < pmax)
+    *p++ = toupper (*string++);
+  *p = '\0';
+}
+
+
+Wad_name_c::Wad_name_c (const char *fmt, ...)
+{
+  va_list list;
+  va_start (list, fmt);
+  y_vsnprintf (name, sizeof name, fmt, list);
+  va_end (list);
+  y_strupr (name);
+}
+
+
+int Wad_name_c::cmp (wad_name_t name)
+{
+  return y_strnicmp (this->name, name, WAD_NAME);
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/wadnamec.h	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,23 @@
+/*
+ *	wadnamec.h
+ *	AYM 2000-04-11
+ */
+
+
+#ifndef YH_WADNAMEC
+#define YH_WADNAMEC
+
+
+/*
+ *	Wad_name_c - a lump name
+ */
+struct Wad_name_c
+{
+  Wad_name_c (const char *string);
+  Wad_name_c (const char *fmt, ...);
+  int cmp (wad_name_t name);
+  char name[WAD_NAME + 1];
+};
+
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/wadres.cc	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,40 @@
+/*
+ *	wadres.cc
+ *	Wadres class
+ *	AYM 2000-04-07
+ */
+
+
+/*
+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 "wadres.h"
+
+
+Wad_res::Wad_res (MDirPtr *md) : sprites (md, &master_dir_serial)
+{
+  ;
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/wadres.h	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,59 @@
+/*
+ *	wadres.h
+ *	Wadres class
+ *	AYM 2000-04-06
+ */
+
+
+/*
+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.
+*/
+
+
+#ifndef YH_WADRES  /* DO NOT INSERT ANYTHING BEFORE THIS LINE */
+#define YH_WADRES
+
+
+#include "spritdir.h"
+
+
+/* This class is mostly a collection of other class. It does not
+   much more than neatly grouping all objects that have the same
+   lifetime and dependencies. */
+class Wad_res
+{
+  public :
+    Wad_res (MDirPtr *md);
+    Sprite_dir sprites;
+    /* To be added here :
+       - Lump_dir patches
+       - Lump_dir flats
+       - Lump_cache textures (TEXTURE[12])
+       - Lump_cache pnames   (PNAMES)
+       - Lump_cache palette  (PLAYPAL, first 768 bytes) */
+  private :
+};
+
+
+extern Wad_res wad_res;
+
+
+#endif  /* DO NOT ADD ANYTHING AFTER THIS LINE */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/wads.cc	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,270 @@
+/*
+ *	wads.cc
+ *	Wad file routines
+ *	BW & RQ sometime in 1993 or 1994.
+ */
+
+
+/*
+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 "serialnum.h"
+#include "wads.h"
+
+
+MDirPtr MasterDir = NULL;		// The master directory
+Serial_num master_dir_serial;		// The revision# thereof
+
+
+/*
+ *	file_read_i16 - read little-endian 16-bit signed integers from a file
+ *
+ *	Return 0 on success, non-zero on failure.
+ */
+int file_read_i16 (FILE *fp, i16 *buf, long count)
+{
+  while (count-- > 0)
+    *buf = getc (fp) | (getc (fp) << 8);
+  return feof (fp) || ferror (fp);
+}
+
+
+/*
+ *	file_read_i32 - read little-endian 32-bit signed integers from a file
+ *
+ *	Return 0 on success, non-zero on failure.
+ */
+int file_read_i32 (FILE *fp, i32 *buf, long count)
+{
+  while (count-- > 0)
+  {
+    *buf++ =    getc (fp)
+      | (      getc (fp) << 8)
+      | ((i32) getc (fp) << 16)
+      | ((i32) getc (fp) << 24);
+  }
+  return feof (fp) || ferror (fp);
+}
+
+
+/*
+ *	file_read_vbytes - read bytes from file
+ *
+ *	Return the number of bytes read.
+ */
+long file_read_vbytes (FILE *fp, void *buf, long count)
+{
+  long bytes_read_total;
+  size_t bytes_read;
+  size_t bytes_to_read;
+
+  bytes_read_total = 0;
+  bytes_to_read    = 0x8000;
+  while (count > 0)
+  {
+    if (count <= 0x8000)
+      bytes_to_read = (size_t) count;
+    bytes_read = fread (buf, 1, bytes_to_read, fp);
+    bytes_read_total += bytes_read;
+    if (bytes_read != bytes_to_read)
+      break;
+    buf = (char *) buf + bytes_read;
+    count -= bytes_read;
+  }
+  return bytes_read_total;
+}
+
+
+/*
+ *	file_read_bytes - read bytes from a file
+ *
+ *	Return 0 on success, non-zero on failure.
+ */
+int file_read_bytes (FILE *fp, void *buf, long count)
+{
+  return file_read_vbytes (fp, buf, count) != count;
+}
+
+
+/*
+ *	file_write_i16 - write a little-endian 16-bit signed integer to a file
+ *
+ *	Does no error checking.
+ */
+void file_write_i16 (FILE *fd, i16 buf)
+{
+  putc (       buf & 0xff, fd);
+  putc ((buf >> 8) & 0xff, fd);
+}
+
+
+/*
+ *	file_write_i32 - write little-endian 32-bit signed integers to a file
+ *
+ *	Does no error checking.
+ */
+void file_write_i32 (FILE *fd, i32 buf, long count)
+{
+  /* It would probably be more efficient to swap bytes in-core
+     and write the whole i32 at once. */
+  while (count-- > 0)
+  {
+    putc (        buf & 0xff, fd);
+    putc ((buf >>  8) & 0xff, fd);
+    putc ((buf >> 16) & 0xff, fd);
+    putc ((buf >> 24) & 0xff, fd);
+  }
+}
+
+
+/*
+ *	file_write_name - write directory entry name to file
+ *
+ *	Write to file <fd> the directory entry name contained in
+ *	<name>. The string written in the file is exactly the
+ *	same as the string contained in <name> except that :
+ *
+ *	- only the first WAD_NAME characters of <name> are
+ *	  used, or up to the first occurrence of a NUL,
+ *	  
+ *	- all letters are forced to upper case,
+ *
+ *	- if necessary, the string is padded to WAD_NAME
+ *	  characters with NULs.
+ *
+ *	Does no error checking.
+ */
+void file_write_name (FILE *fd, const char *name)
+{
+  const unsigned char *const p0 = (const unsigned char *) name;
+  const unsigned char *p = p0;  // "unsigned" for toupper()'s sake
+
+  for (; p - p0 < (ptrdiff_t) WAD_NAME && *p; p++)
+    putc (toupper (*p), fd);
+  for (; p - p0 < (ptrdiff_t) WAD_NAME; p++)
+    putc ('\0', fd);
+}
+
+
+/*
+   find an entry in the master directory
+*/
+
+MDirPtr FindMasterDir (MDirPtr from, const char *name)
+{
+  while (from)
+  {
+    if (! y_strnicmp (from->dir.name, name, WAD_NAME))
+      break;
+    from = from->next;
+  }
+  return from;
+}
+
+
+/*
+ *	Find an entry in the master directory
+ */
+MDirPtr FindMasterDir (MDirPtr from, const char *name1, const char *name2)
+{
+  while (from)
+    {
+    if (! y_strnicmp (from->dir.name, name1, WAD_NAME)
+     || ! y_strnicmp (from->dir.name, name2, WAD_NAME))
+      break;
+    from = from->next;
+    }
+  return from;
+}
+
+
+/*
+   output bytes to a binary file with error checking
+*/
+
+void WriteBytes (FILE *file, const void *buf, long size)
+{
+  if (! Registered)
+    return;
+  while (size > 0x8000)
+  {
+    if (fwrite (buf, 1, 0x8000, file) != 0x8000)
+      fatal_error ("error writing to file");
+    buf = (const char *) buf + 0x8000;
+    size -= 0x8000;
+  }
+  if (fwrite (buf, 1, size, file) != (size_t) size)
+    fatal_error ("error writing to file");
+}
+
+
+/*
+ *	copy_bytes - copy bytes from a binary file to another
+ *
+ *	FIXME it's silly to allocate such a large buffer on
+ *	memory constrained systems. The function should be able
+ *	to fall back on a smaller buffer.
+ *
+ *	Return 0 on success, 1 if there was a read error on
+ *	source file, 2 if there was a write error on destination
+ *	file.
+ */
+int copy_bytes (FILE *dest, FILE *source, long size)
+{
+  int          rc      = 0;
+  void        *data    = 0;
+  const size_t chunksz = 0x4000;
+
+  data = GetFarMemory (chunksz + 2);
+  while (size > chunksz)
+  {
+    if (fread (data, 1, chunksz, source) != chunksz)
+    {
+      rc = 1;
+      goto byebye;
+    }
+    if (fwrite (data, 1, chunksz, dest) != chunksz)
+    {
+      rc = 2;
+      goto byebye;
+    }
+    size -= chunksz;
+  }
+  if (fread (data, 1, size, source) != (size_t) size)
+  {
+    rc = 1;
+    goto byebye;
+  }
+  if (fwrite (data, 1, size, dest) != (size_t) size)
+  {
+    rc = 2;
+    goto byebye;
+  }
+
+byebye:
+  if (data != 0)
+    FreeFarMemory (data);
+  return rc;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/wads.h	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,61 @@
+/*
+ *	wads.h
+ *	AYM 1998-11-25
+ */
+
+
+#ifndef YH_WADS  /* DO NOT INSERT ANYTHING BEFORE THIS LINE */
+#define YH_WADS
+
+
+int  file_read_i16    (FILE *,  i16 *buf, long count = 1);
+int  file_read_i32    (FILE *,  i32 *buf, long count = 1);
+long file_read_vbytes (FILE *, void *buf, long count);
+int  file_read_bytes  (FILE *, void *buf, long count);
+void file_write_i16   (FILE *,  i16 buf);
+void file_write_i32   (FILE *,  i32 buf, long count = 1);
+void file_write_name  (FILE *, const char *name);
+void WriteBytes       (FILE *, const void *, long);
+int  copy_bytes       (FILE *dest, FILE *source, long size);
+
+#if 0
+void wad_seek        (WadPtr, long offset);
+void wad_read_bytes  (WadPtr, void *buf, long count);
+long wad_read_vbytes (WadPtr, void *buf, long count);
+ i16 wad_read_i16    (WadPtr);
+void wad_read_i16    (WadPtr,  i16 *buf);
+void wad_read_i32    (WadPtr,  i32 *buf, long count = 1);
+#endif
+
+
+#if 0
+/*
+ *	flat_name_cmp
+ *	Compare two flat names like strcmp() compares two strings.
+ */
+inline int flat_name_cmp (const char *name1, const char *name2)
+{
+}
+
+
+/*
+ *	tex_name_cmp
+ *	Compare two texture names like strcmp() compares two strings.
+ *	T
+ */
+inline int tex_name_cmp (const char *name1, const char *name2)
+{
+}
+
+
+/*
+ *	sprite_name_cmp
+ *	Compare two sprite names like strcmp() compares two strings.
+ */
+inline int sprite_name_cmp (const char *name1, const char *name2)
+{
+}
+#endif
+
+
+#endif  /* DO NOT ADD ANYTHING AFTER THIS LINE */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/wads2.cc	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,977 @@
+/*
+ *	wads2.cc
+ *	Wads functions that are not needed during editing.
+ *	AYM 1998-08-09
+ */
+
+
+/*
+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 "game.h"	/* yg_picture_format */
+#include "serialnum.h"
+#include "wadfile.h"
+#include "wadlist.h"
+#include "wads.h"
+#include "wads2.h"
+
+
+static char *locate_pwad (const char *filename);
+static int level_name_order (const void *p1, const void *p2);
+
+
+/*
+ *	OpenMainWad - open the iwad
+ *
+ *	Open the main wad file, read in its directory and create
+ *	the master directory.
+ *
+ *	Return 0 on success, non-zero on failure.
+ */
+int OpenMainWad (const char *filename)
+{
+MDirPtr lastp, newp;
+long n;
+Wad_file *wf;
+
+/* open the wad file */
+printf ("Loading iwad: %s...\n", filename);
+wf = BasicWadOpen (filename, yg_picture_format);
+if (wf == 0)
+   return 1;
+if (strncmp (wf->type, "IWAD", 4))
+   warn ("%.128s: is a pwad, not an iwad. Will use it anyway.\n", filename);
+
+/* create the master directory */
+lastp = NULL;
+for (n = 0; n < wf->dirsize; n++)
+   {
+   newp = (MDirPtr) GetMemory (sizeof (struct MasterDirectory));
+   newp->next = NULL;
+   newp->wadfile = wf;
+   memcpy (&(newp->dir), &(wf->directory[n]), sizeof (struct Directory));
+   if (MasterDir)
+      lastp->next = newp;
+   else
+      MasterDir = newp;
+   lastp = newp;
+   }
+master_dir_serial.bump ();
+
+/* check if registered version */
+if (FindMasterDir (MasterDir, "E2M1") == NULL
+ && FindMasterDir (MasterDir, "MAP01") == NULL
+ && FindMasterDir (MasterDir, "MAP33") == NULL
+ && strcmp (Game, "doom02")
+ && strcmp (Game, "doom04")
+ && strcmp (Game, "doom05")
+ && strcmp (Game, "doompr"))
+   {
+   printf ("   *-----------------------------------------------------*\n");
+   printf ("   | Warning: this is the shareware version of the game. |\n");
+   printf ("   |     You won't be allowed to save your changes.      |\n");
+   printf ("   |       PLEASE REGISTER YOUR COPY OF THE GAME.        |\n");
+   printf ("   *-----------------------------------------------------*\n");
+   Registered = false; // If you remove this, bad things will happen to you...
+   }
+else
+   Registered = true;
+return 0;
+}
+
+
+/*
+ *	OpenPatchWad - add a pwad
+ *
+ *	Open a patch wad file, read in its directory and alter
+ *	the master directory.
+ *
+ *	Return 0 on success, non-zero on failure.
+ */
+int OpenPatchWad (const char *filename)
+{
+Wad_file * wad;
+MDirPtr mdir = 0;
+long n;
+char entryname[WAD_NAME + 1];
+const char *entry_type = 0;
+char *real_name;
+int nitems = 0;		// Number of items in group of flats/patches/sprites
+
+// Look for the file and ignore it if it doesn't exist
+real_name = locate_pwad (filename);
+if (real_name == NULL)
+   {
+   warn ("%.128s: not found.\n", filename);
+   return 1;
+   }
+
+/* open the wad file */
+printf ("Loading pwad: %s...\n", real_name);
+// By default, assume pwads use the normal picture format.
+wad = BasicWadOpen (real_name, YGPF_NORMAL);
+FreeMemory (real_name);
+if (! wad)
+   return 1;
+if (strncmp (wad->type, "PWAD", 4))
+   warn ("%.128s: is an iwad, not a pwad. Will use it anyway.\n", filename);
+
+/* alter the master directory */
+
+/* AYM: now, while the directory is scanned, a state variable is
+   updated. its values are :
+   0    no special state
+   1-11 reading level lumps */
+/* AYM 1998-11-15: FIXME: to be on the safe side, should consider
+   FF_END to end a group of flats if the following entry is neither
+   F_END nor F?_START. */
+
+int state = 0;
+int replaces = 0;
+int state_prev;
+int replaces_prev;
+int names = 0;		// Number of names already printed on current line
+const char *entry_type_prev;
+typedef char level_list_item_t[WAD_NAME];
+level_list_item_t *level_list = 0;
+size_t nlevels = 0;
+for (n = 0; n < wad->dirsize; n++)
+   {
+   strncpy (entryname, wad->directory[n].name, WAD_NAME);
+   entryname[WAD_NAME] = '\0';
+   state_prev = state;
+   replaces_prev = replaces;
+   entry_type_prev = entry_type;
+   if (state == 0)
+      {
+      if (! strcmp (entryname, "F_START")
+       || ! strcmp (entryname, "P_START")
+       || ! strcmp (entryname, "S_START"))
+	 {
+	 entry_type = "label";
+	 replaces   = 0;
+	 }
+      // DeuTex puts flats between FF_START and FF_END/F_END.
+      // All lumps between those markers are assumed
+      // to be flats.
+      else if (! strncmp (entryname, "FF_START", WAD_NAME))
+	 {
+	 state      = 'f';
+	 entry_type = "group of flats";
+	 replaces   = 0;
+         nitems     = 0;
+	 }
+      // DeuTex puts patches between PP_START and PP_END.
+      // All lumps between those markers are assumed
+      // to be patches.
+      else if (! strncmp (entryname, "PP_START", WAD_NAME))
+	 {
+	 state      = 'p';
+	 entry_type = "group of patches";
+	 replaces   = 0;
+         nitems     = 0;
+	 }
+      // DeuTex puts patches between SS_START and SS_END/S_END.
+      // All lumps between those markers are assumed
+      // to be sprites.
+      else if (! strncmp (entryname, "SS_START", WAD_NAME))
+	 {
+	 state      = 's';
+	 entry_type = "group of sprites";
+	 replaces   = 0;
+         nitems     = 0;
+	 }
+      else
+	 {
+	 mdir = FindMasterDir (MasterDir, entryname);
+	 replaces = mdir != NULL;
+	 /* if it is a level, do the same thing for the next 10 entries too */
+	 if (levelname2levelno (entryname))
+	    {
+	    state = 11;
+	    entry_type = "level";
+	    // Add to list of level names
+	    {
+	    level_list_item_t *new_list;
+	    new_list = (level_list_item_t *)
+	       realloc (level_list, (nlevels + 1) * sizeof *level_list);
+	    if (new_list != 0)
+	       {
+	       level_list = new_list;
+	       strncpy (level_list[nlevels], entryname, sizeof *level_list);
+	       nlevels++;
+	       }
+	    }
+	    }
+	 else
+	    entry_type = "entry";
+	 }
+      if (n == 0
+	  || state_prev      != state
+	  || replaces_prev   != replaces
+	  || entry_type_prev != entry_type)
+         {
+	 if (n > 0)
+	    verbmsg ("\n");
+	 names = 0;
+	 verbmsg ("  %s %s", replaces ? "Updating" : "Adding new", entry_type);
+         }
+      if (names >= 6)
+         {
+	 verbmsg ("\n  %-*s %-*s",
+	     strlen (replaces ? "Updating" : "Adding new"), "",
+	     strlen (entry_type), "");
+	 names = 0;
+         }
+      verbmsg  (" %-*s", WAD_NAME, entryname);
+      names++;
+      if ((*entry_type == 'm' || *entry_type == 'l') && wad->directory[n].size)
+	 verbmsg (" warning: non-zero length (%ld)", wad->directory[n].size);
+      }
+   // Either F_END or FF_END mark the end of a
+   // DeuTex-generated group of flats.
+   else if (state == 'f')
+      {
+      if (! strncmp (entryname, "F_END", WAD_NAME)
+	  || ! strncmp (entryname, "FF_END", WAD_NAME))
+         {
+	 state = 0;
+         verbmsg ("/%.*s (%d flats)", WAD_NAME, entryname, nitems);
+         }
+      // Of course, F?_START and F?_END don't count
+      // toward the number of flats in the group.
+      else if (! (*entryname == 'F'
+                  && (! strncmp (entryname + 2, "_START", 6)
+                      || ! strcmp (entryname + 2, "_END"))))
+         nitems++;
+      }
+   // PP_END marks the end of a DeuTex-generated group of patches.
+   else if (state == 'p')
+      {
+      if (! strncmp (entryname, "PP_END", WAD_NAME))
+         {
+         state = 0;
+         verbmsg ("/PP_END (%d patches)", nitems);
+         }
+      // Of course, P?_START and P?_END don't count
+      // toward the number of flats in the group.
+      else if (! (*entryname == 'P'
+                  && (! strncmp (entryname + 2, "_START", 6)
+                      || ! strcmp (entryname + 2, "_END"))))
+         nitems++;
+      }
+   // Either S_END or SS_END mark the end of a
+   // DeuTex-generated group of sprites.
+   else if (state == 's')
+      {
+      if (! strncmp (entryname, "S_END", WAD_NAME)
+	  || ! strncmp (entryname, "SS_END", WAD_NAME))
+         {
+	 state = 0;
+         verbmsg ("/%.*s (%d sprites)", WAD_NAME, entryname, nitems);
+         }
+      // Of course, S?_START and S?_END don't count
+      // toward the number of sprites in the group.
+      else if (! (*entryname == 'S'
+                  && (! strncmp (entryname + 2, "_START", 6)
+                      || ! strcmp (entryname + 2, "_END"))))
+         nitems++;
+      }
+     
+   /* if this entry is not in the master directory, then add it */
+   if (!replaces)
+      {
+      mdir = MasterDir;
+      while (mdir->next)
+	 mdir = mdir->next;
+      mdir->next = (MDirPtr) GetMemory (sizeof (struct MasterDirectory));
+      mdir = mdir->next;
+      mdir->next = NULL;
+      }
+   /* else, simply replace it */
+   mdir->wadfile = wad;
+   memcpy (&(mdir->dir), &(wad->directory[n]), sizeof (struct Directory));
+   mdir = mdir->next;
+
+   if (state > 0 && state <= 11)
+      state--;
+   }
+verbmsg ("\n");
+master_dir_serial.bump ();
+
+// Print list of levels found in this pwad
+if (level_list != 0)
+   {
+   printf ("  Levels: ");
+   qsort (level_list, nlevels, sizeof *level_list, level_name_order);
+   for (size_t n = 0; n < nlevels; n++)
+      {
+      int prev = n > 0           ? levelname2rank (level_list[n - 1]) : INT_MIN;
+      int cur  =                   levelname2rank (level_list[n    ]);
+      int next = n + 1 < nlevels ? levelname2rank (level_list[n + 1]) : INT_MAX;
+      if (cur != prev + 1 || cur != next - 1)
+         {
+         if (cur == prev + 1)
+	    putchar ('-');
+	 else if (n > 0)
+	    putchar (' ');
+         printf ("%.*s", (int) sizeof *level_list, level_list[n]);
+         }
+      }
+   putchar ('\n');
+   free (level_list);
+   }
+return 0;
+}
+
+
+/*
+ *	level_name_order - -cmp-style comparison of two level names
+ */
+static int level_name_order (const void *p1, const void *p2)
+{
+return levelname2rank ((const char *) p1)
+     - levelname2rank ((const char *) p2);
+}
+
+
+/*
+ *	CloseWadFiles - close all wads
+ *
+ *	Close all the wad, deallocating the wad file structures.
+ */
+void CloseWadFiles ()
+{
+MDirPtr curd, nextd;
+
+// Close the wad files
+Wad_file *wf;
+wad_list.rewind ();
+while (wad_list.get (wf))
+   wad_list.del ();
+
+// Delete the master directory
+curd = MasterDir;
+MasterDir = NULL;
+while (curd)
+   {
+   nextd = curd->next;
+   FreeMemory (curd);
+   curd = nextd;
+   }
+master_dir_serial.bump ();
+}
+
+
+/*
+ *	CloseUnusedWadFiles - forget unused patch wad files
+ */
+void CloseUnusedWadFiles ()
+{
+Wad_file *wf;
+wad_list.rewind ();
+while (wad_list.get (wf))
+   {
+   // Check if the wad file is used by a directory entry
+   MDirPtr mdir = MasterDir;
+   while (mdir && mdir->wadfile != wf)
+      mdir = mdir->next;
+   if (mdir == 0)
+      wad_list.del ();
+   }
+}
+
+
+/*
+ *	BasicWadOpen - open a wad
+ *
+ *	Basic opening of wad file and creation of node in Wad
+ *	linked list.
+ *
+ *	Return a null pointer on error.
+ */
+Wad_file *BasicWadOpen (const char *filename, ygpf_t pic_format)
+{
+bool fail = false;
+
+/* If this wad is already open, close it first (it's not always
+   possible to open the same file twice). Also position the
+   wad_list pointer on the old wad (or at the end of the list if
+   this is a new wad) so that the reopening a wad doesn't change
+   it's relative position in the list.
+   
+   FIXME if reopening fails, we're left in the cold. I'm not
+   sure how to avoid that, though. */
+{
+   Wad_file *dummy;
+   wad_list.rewind ();
+   while (wad_list.get (dummy))
+      if (fncmp (filename, dummy->filename) == 0)
+	 {
+	 wad_list.del ();
+	 break;
+	 }
+}
+
+// Create a new Wad_file
+Wad_file *wf = new Wad_file;
+wf->pic_format_ = pic_format;
+wf->directory   = 0;
+wf->filename    = (char *) GetMemory (strlen (filename) + 1);
+strcpy (wf->filename, filename);
+
+// Open the wad and read its header.
+wf->fp = fopen (filename, "rb");
+if (wf->fp == 0)
+   {
+   printf ("%.128s: %s\n", filename, strerror (errno));
+   fail = true;
+   goto byebye;
+   }
+{
+bool e = file_read_bytes (wf->fp, wf->type, 4);
+e     |= file_read_i32   (wf->fp, &wf->dirsize);
+e     |= file_read_i32   (wf->fp, &wf->dirstart);
+if (e || memcmp (wf->type, "IWAD", 4) != 0 && memcmp (wf->type, "PWAD", 4) != 0)
+   {
+   printf ("%.128s: not a wad (bad header)\n", filename);
+   fail = true;
+   goto byebye;
+   }
+}
+verbmsg ("  Type %.4s, directory has %ld entries at offset %08lXh\n",
+   wf->type, (long) wf->dirsize, (long) wf->dirstart);
+
+// Load the directory of the wad
+wf->directory = (DirPtr) GetMemory ((long) sizeof (struct Directory)
+   * wf->dirsize);
+if (fseek (wf->fp, wf->dirstart, SEEK_SET) != 0)
+   {
+   printf ("%.128s: can't seek to directory at %08lXh\n",
+      filename, wf->dirstart);
+   fail = true;
+   goto byebye;
+   }
+for (i32 n = 0; n < wf->dirsize; n++)
+   {
+   bool e  = file_read_i32   (wf->fp, &wf->directory[n].start);
+   e      |= file_read_i32   (wf->fp, &wf->directory[n].size);
+   e      |= file_read_bytes (wf->fp, wf->directory[n].name, WAD_NAME);
+   if (e)
+      {
+      printf ("%.128s: read error on directory entry %ld\n", filename, (long)n);
+      fail = true;
+      goto byebye;
+      }
+   }
+
+// Insert the new wad in the list
+wad_list.insert (wf);
+
+byebye:
+if (fail)
+  {
+  delete wf;
+  return 0;
+  }
+return wf;
+}
+
+
+/*
+ *	ListMasterDirectory - list the master directory
+ */
+void ListMasterDirectory (FILE *file)
+{
+char dataname[WAD_NAME + 1];
+MDirPtr dir;
+char key;
+int lines = 3;
+
+dataname[WAD_NAME] = '\0';
+fprintf (file, "The Master Directory\n");
+fprintf (file, "====================\n\n");
+fprintf (file, "NAME____  FILE______________________________________________"
+   "  SIZE__  START____\n");
+for (dir = MasterDir; dir; dir = dir->next)
+   {
+   strncpy (dataname, dir->dir.name, WAD_NAME);
+   fprintf (file, "%-*s  %-50s  %6ld  x%08lx\n",
+    WAD_NAME, dataname, dir->wadfile->pathname (),
+    dir->dir.size, dir->dir.start);
+   if (file == stdout && lines++ > screen_lines - 4)
+      {
+      lines = 0;
+      printf ("['Q' followed by Return to abort, Return only to continue]");
+      key = getchar ();
+      printf ("\r%57s\r", "");
+      if (key == 'Q' || key == 'q')
+	 {
+         getchar ();  // Read the '\n'
+         break;
+         }
+      }
+   }
+}
+
+
+/*
+ *	ListFileDirectory - list the directory of a wad
+ */
+void ListFileDirectory (FILE *file, const Wad_file *wad)
+{
+char dataname[WAD_NAME + 1];
+char key;
+int lines = 5;
+long n;
+
+dataname[WAD_NAME] = '\0';
+fprintf (file, "Wad File Directory\n");
+fprintf (file, "==================\n\n");
+fprintf (file, "Wad File: %s\n\n", wad->pathname ());
+fprintf (file, "NAME____  SIZE__  START____  END______\n");
+for (n = 0; n < wad->dirsize; n++)
+   {
+   strncpy (dataname, wad->directory[n].name, WAD_NAME);
+   fprintf (file, "%-*s  %6ld  x%08lx  x%08lx\n",
+     WAD_NAME, dataname,
+     wad->directory[n].size,
+     wad->directory[n].start,
+     wad->directory[n].size + wad->directory[n].start - 1);
+   if (file == stdout && lines++ > screen_lines - 4)
+      {
+      lines = 0;
+      printf ("['Q' followed by Return to abort, Return only to continue]");
+      key = getchar ();
+      printf ("\r%57s\r", "");
+      if (key == 'Q' || key == 'q')
+         {
+         getchar ();  // Read the '\n'
+	 break;
+         }
+      }
+   }
+}
+
+
+/*
+ *	BuildNewMainWad - build a new iwad (or pwad)
+ *
+ *	Build a new wad file from master directory.
+ */
+void BuildNewMainWad (const char *filename, bool patchonly)
+{
+FILE *file;
+long counter = 12;
+MDirPtr cur;
+long size;
+long dirstart;
+long dirnum;
+
+/* open the file and store signatures */
+if (patchonly)
+   printf ("Building a compound Patch Wad file \"%s\".\n", filename);
+else
+   printf ("Building a new Main Wad file \"%s\" (size approx 10 MB)\n",
+      filename);
+if (FindMasterDir (MasterDir, "E2M4") == NULL
+ && FindMasterDir (MasterDir, "MAP01") == NULL
+ && FindMasterDir (MasterDir, "MAP33") == NULL
+ && strcmp (Game, "doom02")
+ && strcmp (Game, "doom04")
+ && strcmp (Game, "doom05")
+ && strcmp (Game, "doompr"))
+   fatal_error ("You were warned: you are not allowed to do this.");
+if ((file = fopen (filename, "wb")) == NULL)
+   fatal_error ("unable to open file \"%s\"", filename);
+if (patchonly)
+   WriteBytes (file, "PWAD", 4);
+else
+   WriteBytes (file, "IWAD", 4);
+file_write_i32 (file, 0xdeadbeef);      /* put true value in later */
+file_write_i32 (file, 0xdeadbeef);      /* put true value in later */
+
+/* output the directory data chunks */
+const Wad_file *iwad = 0;	// FIXME unreliable way of knowing the iwad
+wad_list.rewind ();		// got to look into this
+wad_list.get (iwad);
+for (cur = MasterDir; cur; cur = cur->next)
+   {
+   if (patchonly && cur->wadfile == iwad)
+      continue;
+   size = cur->dir.size;
+   counter += size;
+   cur->wadfile->seek (cur->dir.start);
+   if (cur->wadfile->error ())
+      ;  // FIXME
+   if (copy_bytes (file, cur->wadfile->fp, size) != 0)
+      ;  // FIXME
+   printf ("Size: %luK\r", counter / 1024);
+   }
+
+/* output the directory */
+dirstart = counter;
+counter = 12;
+dirnum = 0;
+for (cur = MasterDir; cur; cur = cur->next)
+   {
+   if (patchonly && cur->wadfile == iwad)
+      continue;
+   if (dirnum % 100 == 0)
+      printf ("Outputting directory %04ld...\r", dirnum);
+   if (cur->dir.start)
+      file_write_i32 (file, counter);
+   else
+      file_write_i32 (file, 0);
+   file_write_i32 (file, cur->dir.size);
+   file_write_name (file, cur->dir.name);
+   counter += cur->dir.size;
+   dirnum++;
+   }
+
+/* fix up the number of entries and directory start information */
+if (fseek (file, 4L, 0))
+   fatal_error ("error writing to file");
+file_write_i32 (file, dirnum);
+file_write_i32 (file, dirstart);
+
+/* close the file */
+printf ("                            \r");
+fclose (file);
+}
+
+
+/*
+ *	DumpDirectoryEntry - hexadecimal dump of a lump
+ *
+ *	Dump a directory entry in hex
+ */
+void DumpDirectoryEntry (FILE *file, const char *entryname)
+{
+char dataname[WAD_NAME + 1];
+char key;
+int lines = 5;
+long n = 0;
+unsigned char buf[16];
+const int bytes_per_line = 16;
+
+for (MDirPtr entry = MasterDir; entry != 0; entry = entry->next)
+   {
+   if (y_strnicmp (entry->dir.name, entryname, WAD_NAME) != 0)
+      continue;
+   strncpy (dataname, entry->dir.name, WAD_NAME);
+   dataname[WAD_NAME] = '\0';
+   fprintf (file, "Contents of entry %s (size = %ld bytes):\n",
+      dataname, entry->dir.size);
+   const Wad_file *wf = entry->wadfile;
+   wf->seek (entry->dir.start);
+   for (n = 0; n < entry->dir.size;)
+      {
+      int i;
+      fprintf (file, "%04lX: ", n);
+
+      // Nb of bytes to read for this line
+      long bytes_to_read = entry->dir.size - n;
+      if (bytes_to_read > bytes_per_line)
+	 bytes_to_read = bytes_per_line;
+      long nbytes = wf->read_vbytes (buf, bytes_to_read);
+      if (wf->error ())
+	 break;
+      n += nbytes;
+
+      for (i = 0; i < nbytes; i++)
+	 fprintf (file, " %02X", buf[i]);
+      for (; i < bytes_per_line; i++)
+	 fputs ("   ", file);
+      fprintf (file, "   ");
+
+      for (i = 0; i < nbytes; i++)
+	 {
+	 if (buf[i] >= 0x20
+	    && buf[i] != 0x7f
+#ifdef Y_UNIX
+	    && ! (buf[i] >= 0x80 && buf[i] <= 0xa0)  // ISO 8859-1
+#endif
+	    )
+	    putc (buf[i], file);
+	 else
+	    putc ('.', file);
+	 }
+      putc ('\n', file);
+
+      if (file == stdout && lines++ > screen_lines - 4)
+	 {
+	 lines = 0;
+	 printf ("[%d%% - Q + Return to abort,"
+	     " S + Return to skip this entry,"
+	     " Return to continue]", (int) (n * 100 / entry->dir.size));
+	 key = getchar ();
+	 printf ("\r%68s\r", "");
+	 if (key == 'S' || key == 's')
+	    {
+	    getchar ();  // Read the '\n'
+	    break;
+	    }
+	 if (key == 'Q' || key == 'q')
+	    {
+	    getchar ();  // Read the '\n'
+	    return;
+	    }
+	 }
+      }
+   }
+if (! n)
+   {
+   printf ("Entry not in master directory.\n");
+   return;
+   }
+}
+
+
+
+/*
+ *	SaveDirectoryEntry - write the contents of a lump to a new pwad
+ *
+ *	Save a directory entry to disk
+ */
+void SaveDirectoryEntry (FILE *file, const char *entryname)
+{
+MDirPtr entry;
+
+for (entry = MasterDir; entry; entry = entry->next)
+   if (!y_strnicmp (entry->dir.name, entryname, WAD_NAME))
+      break;
+if (entry)
+   {
+   // Write the header
+   WriteBytes (file, "PWAD", 4);	// Type = PWAD
+   file_write_i32 (file, 1);		// 1 entry in the directory
+   file_write_i32 (file, 12);		// The directory starts at offset 12
+
+   // Write the directory
+   file_write_i32 (file, 28);		// First entry starts at offset 28
+   file_write_i32 (file, entry->dir.size);	// Size of first entry
+   file_write_name (file, entry->dir.name);	// Name of first entry
+
+   // Write the lump data
+   entry->wadfile->seek (entry->dir.start);
+   if (entry->wadfile->error ())
+      {
+      err ("%s: seek error", entryname);
+      return;
+      }
+   int r = copy_bytes (file, entry->wadfile->fp, entry->dir.size);
+   if (r != 0)
+      {
+      if (r == 1)
+	err ("%s: error reading from source wad", entryname);
+      else if (r == 2)
+	err ("%s: error writing to destination wad", entryname);
+      else
+	nf_bug ("%s: copy_bytes() returned %d", entryname, r);
+      return;
+      }
+   }
+else
+   {
+   printf ("Entry not in master directory.\n");
+   return;
+   }
+}
+
+
+/*
+ *	SaveEntryToRawFile - write the contents of a lump to a new file
+ *
+ *	Save a directory entry to disk, without a pwad header
+ */
+void SaveEntryToRawFile (FILE *file, const char *entryname)
+{
+MDirPtr entry;
+
+for (entry = MasterDir; entry; entry = entry->next)
+   if (!y_strnicmp (entry->dir.name, entryname, WAD_NAME))
+      break;
+if (entry)
+   {
+   verbmsg ("Writing %ld bytes starting from offset %lX...\n",
+      (long) entry->dir.size, (unsigned long) entry->dir.start);
+   entry->wadfile->seek (entry->dir.start);
+   if (entry->wadfile->error ())
+      {
+      err ("%s: seek error", entryname);
+      return;
+      }
+   int r = copy_bytes (file, entry->wadfile->fp, entry->dir.size);
+   if (r != 0)
+      {
+      if (r == 1)
+	err ("%s: error reading from source wad", entryname);
+      else if (r == 2)
+	err ("%s: error writing to destination file", entryname);
+      else
+	nf_bug ("%s: copy_bytes() returned %d", entryname, r);
+      return;
+      }
+   }
+else
+   {
+   printf ("[Entry not in master directory]\n");
+   return;
+   }
+}
+
+
+/*
+ *	SaveEntryFromRawFile - encapsulate a raw file in a pwad
+ *
+ *	Encapsulate a raw file in a pwad file
+ */
+void SaveEntryFromRawFile (FILE *file, FILE *raw, const char *entryname)
+{
+long    size;
+char    name8[WAD_NAME];
+
+// Write the header
+WriteBytes (file, "PWAD", 4);		// Type = PWAD
+file_write_i32 (file, 1);		// 1 entry in the directory
+file_write_i32 (file, 12);		// The directory starts at offset 12
+
+// Write the directory
+file_write_i32 (file, 28);		// First entry starts at offset 28
+
+if (fseek (raw, 0L, SEEK_END) != 0)
+   fatal_error ("error reading from raw file");
+size = ftell (raw);
+if (size < 0)
+   fatal_error ("error reading from raw file");
+if (fseek (raw, 0L, SEEK_SET) != 0)
+   fatal_error ("error reading from raw file");
+file_write_i32 (file, size);		// Size of first entry
+
+memset (name8, '\0', WAD_NAME);
+strncpy (name8, entryname, WAD_NAME);
+file_write_name (file, name8);		// Name of first entry
+
+// Write the lump data
+int r = copy_bytes (file, raw, size);
+if (r != 0)
+   {
+   if (r == 1)
+     err ("%s: error reading from source file", entryname);
+   else if (r == 2)
+     err ("%s: error writing to destination wad", entryname);
+   else
+     nf_bug ("%s: copy_bytes() returned %d", entryname, r);
+   return;
+   }
+}
+
+
+/*
+ *	locate_pwad
+ *	Look for a PWAD in the standard directories
+ *	and returns its name in a GetMemory'd buffer
+ *	(or NULL if not found). It's up to the caller
+ *	to free the buffer after use.
+ */
+
+
+/* Directories that are searched for PWADs */
+static const char *standard_directories[] =
+   {
+   "",
+   "~/",                            // "~" means "the user's home directory"
+   "/usr/local/share/games/%s/",    // %s is replaced by <Game>
+   "/usr/share/games/%s/",          // %s is replaced by <Game>
+   "/usr/local/share/games/wads/",
+   "/usr/share/games/wads/",
+   0
+   };
+
+
+static char *locate_pwad (const char *filename)
+{
+al_fext_t ext;
+const char **dirname;
+char *real_basename;
+char *real_name;
+
+// Get the extension in <ext>
+al_fana (filename, NULL, NULL, NULL, ext);
+
+// If it's an absolute name, stop there.
+if (is_absolute (filename))
+   {
+   real_name = (char *) GetMemory (strlen (filename) + 1 + (*ext ? 0 : 4));
+   strcpy (real_name, filename);
+   if (! *ext)
+      strcat (real_name, ".wad");
+   bool r = file_exists (real_name);
+   if (! r)
+      {
+      FreeMemory (real_name);
+      return 0;
+      }
+   return real_name;
+   }
+
+// It's a relative name. If no extension given, append ".wad"
+real_basename = (char *) GetMemory (strlen (filename) + 1 + (*ext ? 0 : 4));
+strcpy (real_basename, filename);
+if (! *ext)
+   strcat (real_basename, ".wad");
+
+// Then search for a file of that name in the standard directories.
+real_name = (char *) GetMemory (Y_FILE_NAME + 1);
+for (dirname = standard_directories; *dirname; dirname++)
+   {
+   if (! strcmp (*dirname, "~/"))
+      if (getenv ("HOME"))
+         {
+	 al_scps (real_name, getenv ("HOME"), Y_FILE_NAME);
+         al_sapc (real_name, '/', Y_FILE_NAME);
+         }
+      else
+	 continue;
+   else
+      y_snprintf (real_name, Y_FILE_NAME + 1, *dirname, Game ? Game : "");
+   al_saps (real_name, real_basename, Y_FILE_NAME);
+   verbmsg ("  Trying \"%s\"... ", real_name);
+   if (file_exists (real_name))
+      {
+      verbmsg ("right on !\n");
+      FreeMemory (real_basename);
+      return real_name;
+      }
+   verbmsg ("nuts\n");
+   }
+FreeMemory (real_name);
+FreeMemory (real_basename);
+return NULL;
+}
+
+
+/* end of file */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/wads2.h	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,29 @@
+/*	
+ *	wads2.h
+ *	Wads functions that are not needed during editing.
+ *	AYM 2000-05-06
+ */
+
+
+#ifndef YH_WADS2  /* DO NOT INSERT ANYTHING BEFORE THIS LINE */
+#define YH_WADS2
+
+
+class Wad_file;
+
+
+int OpenMainWad (const char *);
+int OpenPatchWad (const char *);
+void CloseWadFiles (void);
+void CloseUnusedWadFiles (void);
+Wad_file *BasicWadOpen (const char *, ygpf_t pic_format);
+void ListMasterDirectory (FILE *);
+void ListFileDirectory (FILE *, const Wad_file *);
+void BuildNewMainWad (const char *, bool);
+void DumpDirectoryEntry (FILE *, const char *);
+void SaveDirectoryEntry (FILE *, const char *);
+void SaveEntryToRawFile (FILE *, const char *);
+void SaveEntryFromRawFile (FILE *, FILE *, const char *);
+
+
+#endif  /* DO NOT ADD ANYTHING AFTER THIS LINE */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/warn.cc	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,55 @@
+/*
+ *	warn.cc
+ *	AYM 1999-08-15
+ */
+
+
+/*
+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"
+
+
+/*
+ *	warn
+ *	printf a warning message to stdout.
+ *	If the format string of the previous invocation did not
+ *	end with a '\n', do not prepend the "Warning: " string.
+ *
+ *	FIXME should handle cases where stdout is not available
+ *	(BGI version when in graphics mode).
+ */
+void warn (const char *fmt, ...)
+{
+  static bool start_of_line = true;
+  va_list args;
+
+  if (start_of_line)
+    fputs ("Warning: ", stdout);
+  va_start (args, fmt);
+  vprintf (fmt, args);
+  size_t len = strlen (fmt);
+  start_of_line = len > 0 && fmt[len - 1] == '\n';
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/windim.cc	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,112 @@
+/*
+ *	windim.cc
+ *	Win_dim class - store the width or height of a window
+ *	AYM 2000-05-29
+ */
+
+
+/*
+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 <ctype.h>
+#include "windim.h"
+
+
+// Holds the private data members.
+struct Win_dim_priv
+{
+  int value;
+  bool relative;
+};
+
+
+Win_dim::Win_dim ()
+{
+  p           = new Win_dim_priv;
+  p->value    = 0;
+  p->relative = false;
+}
+
+
+Win_dim::Win_dim (const char *string)
+{
+  p           = new Win_dim_priv;
+  p->value    = 0;
+  p->relative = false;
+  set (string);
+}
+
+
+Win_dim::~Win_dim ()
+{
+  delete p;
+  p = 0;
+}
+
+
+// String -> Win_dim
+int Win_dim::set (const char *string)
+{
+  int  value    = 0;
+  bool relative = false;
+
+  if (! isdigit (*string))
+    return 1;  // Error
+  while (isdigit (*string))
+  {
+    value = 10 * value + dectoi (*string);
+    string++;
+  }
+  if (*string == '%')
+  {
+    relative = true;
+    string++;
+  }
+  if (*string != '\0')
+    return 1;  // Error
+  p->value    = value;
+  p->relative = relative;
+  return 0;
+}
+
+
+// Get numeric value
+int Win_dim::pixels (int ref_pixels)
+{
+  if (p->relative)
+    return ref_pixels * p->value / 100;
+  else
+    return p->value;
+}
+
+
+// Win_dim -> string
+void Win_dim::string (char *buf, size_t buf_size)
+{
+  if (p->relative)
+    y_snprintf (buf, buf_size, "%d%%", p->value);
+  else
+    y_snprintf (buf, buf_size, "%d", p->value);
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/windim.h	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,30 @@
+/*
+ *	windim.h
+ *	Win_dim class - store the width or height of a window
+ *	AYM 2000-05-29
+ */
+
+
+#ifndef YH_WINDIM  /* DO NOT INSERT ANYTHING BEFORE THIS LINE */
+#define YH_WINDIM
+
+
+struct Win_dim_priv;
+
+class Win_dim
+{
+   public:
+     Win_dim ();
+     Win_dim (const char *string);
+     ~Win_dim ();
+     int set (const char *string);
+     int pixels (int ref_pixels);
+     void string (char *buf, size_t buf_size);
+
+   private:
+     Win_dim (const Win_dim&);			// Too lazy to implement it
+     Win_dim& operator= (const Win_dim&);	// Too lazy to implement it
+     struct Win_dim_priv* p;
+};
+
+#endif  /* DO NOT ADD ANYTHING AFTER THIS LINE */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/wstructs.h	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,227 @@
+/*
+ *	wstructs.h
+ *	Wad files data structures.
+ *	BW & RQ sometime in 1993 or 1994.
+ *	FIXME this file should also contain the definitions for
+ *	the wad header and directory entry which are currently
+ *	in yadex.h.
+ */
+
+
+/*
+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.
+*/
+
+
+#ifndef YH_WSTRUCTS	// To prevent multiple inclusion
+#define YH_WSTRUCTS	// To prevent multiple inclusion
+
+
+// FIXME: all identifiers should start with wad_ or WAD_...
+
+
+// Directory
+const size_t WAD_NAME = 8;		// Length of a directory entry name
+typedef char wad_name_t[WAD_NAME];
+typedef struct Directory huge *DirPtr;
+struct Directory
+{
+  i32        start;			// Offset to start of data
+  i32        size;			// Byte size of data
+  wad_name_t name;			// Name of data block
+};
+
+
+// Textures
+const size_t WAD_TEX_NAME = 8;
+typedef char wad_tex_name_t[WAD_TEX_NAME];
+
+
+// Flats
+const size_t WAD_FLAT_NAME = WAD_NAME;
+typedef char wad_flat_name_t[WAD_FLAT_NAME];
+
+
+// Pictures (sprites and patches)
+const size_t WAD_PIC_NAME = WAD_NAME;
+typedef char wad_pic_name_t[WAD_TEX_NAME];
+
+
+// Level objects properties
+typedef i16 wad_coord_t;		// Map (X,Y) coordinates
+typedef i16 wad_ldn_t;			// Linedef#
+typedef i16 wad_sdn_t;			// Sidedef#
+typedef i16 wad_sn_t;			// Sector#
+typedef i16 wad_tag_t;			// Tag
+typedef i16 wad_tn_t;			// Thing# (theor. there might be more)
+typedef i16 wad_vn_t;			// Vertex#
+typedef i16 wad_z_t;			// Map Z coordinate
+
+
+// Things
+const size_t WAD_THING_BYTES       = 10;  // Size in the wad file
+const size_t WAD_HEXEN_THING_BYTES = 20;  // Size in the wad file
+typedef i16 wad_ttype_t;
+typedef i16 wad_tangle_t;
+typedef i16 wad_tflags_t;
+struct Thing
+{
+  wad_coord_t      xpos;		// FIXME rename to "x"
+  wad_coord_t      ypos;		// FIXME rename to "y"
+  wad_tangle_t     angle;
+  wad_ttype_t      type;
+  wad_tflags_t     when;		// FIXME rename to "flags"
+};
+typedef struct
+{
+  i16              tid;
+  wad_coord_t      x;
+  wad_coord_t      y;
+  wad_z_t          height;
+  wad_tangle_t     angle;
+  wad_ttype_t      type;
+  i16              options;
+  u8               special;
+  u8               arg1;
+  u8               arg2;
+  u8               arg3;
+  u8               arg4;
+  u8               arg5;
+} wad_hexen_thing_t;
+typedef struct Thing huge *TPtr;
+
+
+// Linedefs
+const size_t WAD_LINEDEF_BYTES       = 14;  // Size in the wad file
+const size_t WAD_HEXEN_LINEDEF_BYTES = 16;  // Size in the wad file
+typedef i16 wad_ldflags_t;
+typedef i16 wad_ldtype_t;
+struct LineDef
+{
+  wad_vn_t      start;			// # of start vertex
+  wad_vn_t      end;			// # of end vertex
+  wad_ldflags_t flags;
+  wad_ldtype_t  type;
+  wad_tag_t     tag;
+  wad_sdn_t     sidedef1;		// # of first (right) sidedef
+  wad_sdn_t     sidedef2;		// # of second (left) sidedef or 0xffff
+};
+typedef struct
+{
+  wad_vn_t      start;
+  wad_vn_t      end;
+  wad_ldflags_t flags;
+  u8            type;
+  u8            arg1;
+  u8            arg2;
+  u8            arg3;
+  u8            arg4;
+  u8            arg5;
+  wad_sdn_t     sidedef1;
+  wad_sdn_t     sidedef2;
+} wad_hexen_linedef_t;
+typedef struct LineDef huge *LDPtr;
+
+
+// Sidedefs
+const size_t WAD_SIDEDEF_BYTES = 30;	// Size in the wad file
+struct SideDef
+{
+  wad_coord_t    xoff;			// FIXME rename to "xofs"
+  wad_coord_t    yoff;			// FIXME rename to "yofs"
+  wad_tex_name_t tex1;			// Name of upper texture
+  wad_tex_name_t tex2;			// Name of lower texture
+  wad_tex_name_t tex3;			// Name of middle texture
+  wad_sn_t       sector;		// # of adjacent sector
+};
+// (it's the same for Hexen)
+typedef struct SideDef huge *SDPtr;
+
+
+// Vertices
+const size_t WAD_VERTEX_BYTES = 4;	// Size in the wad file
+struct Vertex
+{
+  wad_coord_t x;
+  wad_coord_t y;
+};
+// (it's the same for Hexen)
+typedef struct Vertex huge *VPtr;
+
+
+// Sectors
+const size_t WAD_SECTOR_BYTES = 26;	// Size in the wad file
+typedef i16 wad_stype_t;
+struct Sector
+{
+  wad_z_t         floorh;		// Floor height
+  wad_z_t         ceilh;		// Ceiling height
+  wad_flat_name_t floort;		// Name of floor texture
+  wad_flat_name_t ceilt;		// Name of ceiling texture
+  i16             light;		// Light level (0-255)
+  wad_stype_t     special;		// FIXME rename to "type"
+  wad_tag_t       tag;
+};
+typedef struct Sector huge *SPtr;
+
+
+// The 11 lumps that constitute a Doom/Heretic/Strife level
+typedef enum
+{
+  WAD_LL_LABEL,
+  WAD_LL_THINGS,
+  WAD_LL_LINEDEFS,
+  WAD_LL_SIDEDEFS,
+  WAD_LL_VERTEXES,
+  WAD_LL_SEGS,
+  WAD_LL_SSECTORS,
+  WAD_LL_NODES,
+  WAD_LL_SECTORS,
+  WAD_LL_REJECT,
+  WAD_LL_BLOCKMAP,
+		      // Hexen has a BEHAVIOR lump here
+  WAD_LL__
+} wad_level_lump_no_t;
+
+typedef struct
+{
+  const char *const name;
+  size_t item_size;
+} wad_level_lump_def_t;
+
+const wad_level_lump_def_t wad_level_lump[WAD_LL__] =
+{
+  { 0,          0                 },  // Label -- no fixed name
+  { "THINGS",   WAD_THING_BYTES   },
+  { "LINEDEFS", WAD_LINEDEF_BYTES },
+  { "SIDEDEFS", WAD_SIDEDEF_BYTES },
+  { "VERTEXES", WAD_VERTEX_BYTES  },
+  { "SEGS",     0                 },
+  { "SSECTORS", 0                 },
+  { "NODES",    0                 },
+  { "SECTORS",  WAD_SECTOR_BYTES  },
+  { "REJECT",   0                 },
+  { "BLOCKMAP", 0                 }
+				      // Hexen has a BEHAVIOR lump here
+};
+
+
+#endif  /* DO NOT ADD ANYTHING AFTER THIS LINE */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/x11.cc	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,121 @@
+/*
+ *	x11.c
+ *	X11-specific stuff
+ *	AYM 1999-08-03
+ */
+
+
+/*
+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"
+#ifdef Y_X11
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include "gfx.h"
+#include "x11.h"
+
+
+static bool _have_error = false;
+static unsigned char _error_code;
+
+
+/*
+ *	x_bell
+ *	Ring the bell
+ */
+void x_bell ()
+{
+  if (dpy)
+    XBell (dpy, 0);
+  else
+    nf_bug ("x_bell: not connected");
+}
+
+
+/*
+ *	x_catch_on
+ *	Setup things so that from now on, any X protocol errors
+ *	will be handled by x_error_handler instead of the
+ *	default handler (that has the annoying property of
+ *	calling exit()).
+ */
+void x_catch_on ()
+{
+  XSetErrorHandler (x_error_handler);
+  XSynchronize (dpy, True);
+  x_clear_error ();
+}
+
+
+/*
+ *	x_catch_off
+ *	Restore the default error handler.
+ */
+void x_catch_off ()
+{
+  XSynchronize (dpy, False);
+  XSetErrorHandler (0);
+}
+
+
+/*
+ *	x_error_handler
+ *	An error handler that does not exit.
+ */
+int x_error_handler (Display *dpy, XErrorEvent *e)
+{
+  _have_error = true;
+  _error_code = e->error_code;  // We're only interested in the error code
+  return 0;
+}
+
+
+/*
+ *	x_clear_error
+ *	Call this before attempting an operation that might
+ *	cause an error that you want to catch.
+ */
+void x_clear_error ()
+{
+  _have_error = false;
+}
+
+
+/*
+ *	x_error
+ *	Return a string corresponding to the last error caught
+ *	or a NULL pointer if no error has occured since last
+ *	call to x_clear_error().
+ */
+const char *x_error ()
+{
+  if (! _have_error)
+    return 0;
+  static char buf[100];
+  XGetErrorText (dpy, _error_code, buf, sizeof buf);
+  return buf;
+}
+
+
+#endif  /* DO NOT ADD ANYTHING AFTER THIS LINE */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/x11.h	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,25 @@
+/*
+ *	x11.h
+ *	X11-specific functions
+ *	AYM 1999-08-03
+ */
+
+
+/* Declarations that don't rely on the X11 headers */
+#if defined Y_X11 && ! defined Y_X11_H1
+#define Y_X11_H1
+void x_bell ();
+void x_catch_on ();
+void x_catch_off ();
+void x_clear_error ();
+const char *x_error ();
+#endif
+
+
+/* Declarations that do */
+#if defined Y_X11 && defined X_PROTOCOL && ! defined Y_X11_H2
+#define Y_X11_H2
+int x_error_handler (Display *dpy, XErrorEvent *e);
+#endif
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/x_centre.cc	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,65 @@
+/*
+ *	x_centre.cc
+ *	AYM 1998-11-22
+ */
+
+
+/*
+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 "bitvec.h"
+#include "l_centre.h"
+#include "levels.h"
+#include "s_centre.h"
+#include "t_centre.h"
+#include "v_centre.h"
+#include "x_centre.h"
+
+
+/*
+ *	centre_of_objects
+ *	Return the coordinates of the centre of a group of objects
+ *	of type <obj_type>.
+ */
+void centre_of_objects (int obj_type, SelPtr list, int *x, int *y)
+{
+  switch (obj_type)
+  {
+    case OBJ_LINEDEFS:
+      centre_of_linedefs (list, x, y);
+      break;
+    case OBJ_SECTORS:
+      centre_of_sectors (list, x, y);
+      break;
+    case OBJ_THINGS:
+      centre_of_things (list, x, y);
+      break;
+    case OBJ_VERTICES:
+      centre_of_vertices (list, x, y);
+      break;
+    default:
+      fatal_error ("coo: bad obj_type %d", obj_type);
+  }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/x_centre.h	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,9 @@
+/*
+ *	x_centre.h
+ *	AYM 1998-11-22
+ */
+
+
+void centre_of_objects (int obj_type, SelPtr list, int *x, int *y);
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/x_exchng.cc	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,112 @@
+/*
+ *	x_exchng.cc
+ *	Exchange objects numbers.
+ *	AYM 1999-06-11
+ */
+
+
+/*
+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 "levels.h"
+#include "selectn.h"
+#include "objid.h"
+#include "x_exchng.h"
+
+
+/*
+ *	exchange_objects_numbers
+ *	Exchange the numbers of two objects
+ *
+ *	Return 0 on success, non-zero on failure.
+ */
+int exchange_objects_numbers (int obj_type, SelPtr list, bool adjust)
+{
+  int n1, n2;
+
+  // Must have exactly two objects in the selection
+  if (list == 0 || list->next == 0 || (list->next)->next != 0)
+  {
+    nf_bug ("exchange_object_numbers: wrong objects count.");
+    return 1;
+  }
+  n1 = list->objnum;
+  n2 = (list->next)->objnum;
+
+  if (obj_type == OBJ_LINEDEFS)
+  {
+    struct LineDef swap_buf;
+    swap_buf = LineDefs[n1];
+    LineDefs[n1] = LineDefs[n2];
+    LineDefs[n2] = swap_buf;
+  }
+  else if (obj_type == OBJ_SECTORS)
+  {
+    struct Sector swap_buf;
+    swap_buf = Sectors[n1];
+    Sectors[n1] = Sectors[n2];
+    Sectors[n2] = swap_buf;
+    if (adjust)
+    {
+      for (int n = 0; n < NumSideDefs; n++)
+      {
+	if (SideDefs[n].sector == n1)
+	  SideDefs[n].sector = n2;
+	else if (SideDefs[n].sector == n2)
+	  SideDefs[n].sector = n1;
+      }
+    }
+  }
+  else if (obj_type == OBJ_THINGS)
+  {
+    struct Thing swap_buf;
+    swap_buf = Things[n1];
+    Things[n1] = Things[n2];
+    Things[n2] = swap_buf;
+  }
+  else if (obj_type == OBJ_VERTICES)
+  {
+    struct Vertex swap_buf;
+    swap_buf = Vertices[n1];
+    Vertices[n1] = Vertices[n2];
+    Vertices[n2] = swap_buf;
+    if (adjust)
+    {
+      for (int n = 0; n < NumLineDefs; n++)
+      {
+	if (LineDefs[n].start == n1)
+	  LineDefs[n].start = n2;
+	else if (LineDefs[n].start == n2)
+	  LineDefs[n].start = n1;
+	if (LineDefs[n].end == n1)
+	  LineDefs[n].end = n2;
+	else if (LineDefs[n].end == n2)
+	  LineDefs[n].end = n1;
+      }
+    }
+  }
+  return 0;
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/x_exchng.h	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,9 @@
+/*
+ *	x_exchng.h
+ *	AYM 1999-06-11
+ */
+
+
+int exchange_objects_numbers (int obj_type, SelPtr list, bool adjust);
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/x_hover.cc	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,425 @@
+/*
+ *	x_hover.cc
+ *	AYM 2000-11-08
+ */
+
+
+/*
+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 <math.h>
+#include <vector>
+#include <algorithm>
+#include "drawmap.h"
+#include "levels.h"
+#include "objid.h"
+#include "x_hover.h"
+
+
+class Close_obj
+{
+  public :
+    Close_obj () { nil (); }
+    void nil ()
+    {
+      obj.nil ();
+      distance = ULONG_MAX;
+      radius   = INT_MAX;
+      inside   = false;
+    }
+    bool operator== (const Close_obj& other) const
+    {
+      if (inside == other.inside
+	 && radius == other.radius
+	 && distance == other.distance)
+       return true;
+      return false;
+    }
+    bool operator< (const Close_obj& other) const
+    {
+      if (inside && ! other.inside)
+	return true;
+      if (! inside && other.inside)
+	return false;
+
+      // Small objects should "mask" large objects
+      if (radius < other.radius)
+	return true;
+      if (radius > other.radius)
+	return false;
+
+      if (distance < other.distance)
+	return true;
+      if (distance > other.distance)
+	return false;
+
+      return radius < other.radius;
+    }
+    bool operator<= (const Close_obj& other) const
+    {
+      return *this == other || *this < other;
+    }
+    Objid  obj;
+    double distance;
+    bool   inside;
+    int    radius;
+};
+
+
+static const Close_obj& get_cur_linedef (int x, int y);
+static const Close_obj& get_cur_sector  (int x, int y);
+static const Close_obj& get_cur_thing   (int x, int y);
+static const Close_obj& get_cur_vertex  (int x, int y);
+
+
+/*
+ *	GetCurObject - determine which object is under the pointer
+ * 
+ *	Set <o> to point to the object under the pointer (map
+ *	coordinates (<x>, <y>). If several objects are close
+ *	enough to the pointer, the smallest object is chosen.
+ */
+void GetCurObject (Objid& o, int objtype, int x, int y)
+{
+switch (objtype)
+   {
+   case OBJ_THINGS:
+     {
+       o = get_cur_thing (x, y).obj;
+       return;
+     }
+
+   case OBJ_VERTICES:
+     {
+       o = get_cur_vertex (x, y).obj;
+       return;
+     }
+
+   case OBJ_LINEDEFS:
+     {
+       o = get_cur_linedef (x, y).obj;
+       return;
+     }
+
+   case OBJ_SECTORS:
+     {
+       o = get_cur_sector (x, y).obj;
+       return;
+     }
+
+   case OBJ_ANY:
+     {
+       std::vector<Close_obj> v;
+       v.push_back (get_cur_linedef (x, y));
+       v.push_back (get_cur_thing   (x, y));
+       v.push_back (get_cur_vertex  (x, y));
+       sort (v.begin (), v.end ());
+       if (v[0].obj ())
+       {
+	 o = v[0].obj;
+	 return;
+       }
+       o = get_cur_sector (x, y).obj;
+       return;
+     }
+
+   default:
+     nf_bug ("GetCurObject: objtype %d", (int) objtype);
+     o.nil ();
+     return;
+   }
+}
+
+
+/*
+ *	get_cur_linedef - determine which linedef is under the pointer
+ */
+static const Close_obj& get_cur_linedef (int x, int y)
+{
+  static Close_obj object;
+  const int screenslack = 15;			// Slack in pixels
+  double mapslack = fabs (screenslack / Scale);	// Slack in map units
+  int xmin = (int) (x - mapslack + 0.5);
+  int xmax = (int) (x + mapslack + 0.5);
+  int ymin = (int) (y - mapslack + 0.5);
+  int ymax = (int) (y + mapslack + 0.5);
+  ObjectsNeeded (OBJ_LINEDEFS, OBJ_VERTICES, 0);
+  object.nil ();
+  for (int n = 0; n < NumLineDefs; n++)
+  {
+    int x0 = Vertices[LineDefs[n].start].x;
+    int y0 = Vertices[LineDefs[n].start].y;
+    int x1 = Vertices[LineDefs[n].end].x;
+    int y1 = Vertices[LineDefs[n].end].y;
+    int dx;
+    int dy;
+
+    /* Skip all lines of which all points are more than <mapslack>
+       units away from (x,y). In a typical level, this test will
+       filter out all the linedefs but a handful. */
+    if (x0 < xmin && x1 < xmin
+     || x0 > xmax && x1 > xmax
+     || y0 < ymin && y1 < ymin
+     || y0 > ymax && y1 > ymax)
+      continue;
+
+    /* This is where it gets ugly. We're trying to calculate the
+       distance between the pointer (x,y) and the linedef. Doing that
+       rigorously involves doing an orthogonal projection. I use
+       something simpler (for me).
+
+       If the pointer is not within the ends of the linedef, I calculate
+       the distance between the pointer and the closest end.
+
+       If the pointer is within the ends of the linedef, I calculate
+       what the ordinate would be for a point of the linedef that had
+       the same abscissa as the pointer. Then I calculate the difference
+       between that and the actual ordinate of the pointer and I call
+       that the distance. It's a gross approximation but, in practice,
+       it gives quite satisfactory results. Of course, for lines where
+       dy > dx, the abscissa is y and the ordinate is x.
+       -- AYM 1998-06-29 */
+    dx = x1 - x0;
+    dy = y1 - y0;
+    double dist = ULONG_MAX;
+    // The linedef is rather horizontal
+    if (abs (dx) > abs (dy))
+    {
+      /* Are we to the left of the leftmost end or to the right of the
+	 rightmost end or between the two ? */
+      if (x < (dx > 0 ? x0 : x1))
+	dist = hypot (x - (dx > 0 ? x0 : x1),
+		      y - (dx > 0 ? y0 : y1));
+      else if (x > (dx > 0 ? x1 : x0))
+	dist = hypot (x - (dx > 0 ? x1 : x0),
+		      y - (dx > 0 ? y1 : y0));
+      else
+	dist = fabs (y0 + ((double) dy)/dx * (x - x0) - y);
+    }
+    // The linedef is rather vertical
+    else
+    {
+      /* Are we above the high end or below the low end or in between ? */
+      if (y < (dy > 0 ? y0 : y1))
+	dist = hypot (x - (dy > 0 ? x0 : x1),
+		      y - (dy > 0 ? y0 : y1));
+      else if (y > (dy > 0 ? y1 : y0))
+	dist = hypot (x - (dy > 0 ? x1 : x0),
+		      y - (dy > 0 ? y1 : y0));
+      else
+	dist = fabs (x0 + ((double) dx)/dy * (y - y0) - x);
+    }
+    if (dist <= object.distance  /* "<=" because if there are superimposed
+				    linedefs, we want to return the
+				    highest-numbered one. */
+       && dist <= mapslack)
+    {
+      object.obj.type = OBJ_LINEDEFS;
+      object.obj.num  = n;
+      object.distance = dist;
+      object.radius   = (int) (hypot (dx, dy) / 2);
+      object.inside   = dist < 2 * Scale;
+    }
+  }
+  return object;
+}
+
+
+/*
+ *	get_cur_sector - determine which sector is under the pointer
+ */
+static const Close_obj& get_cur_sector (int x, int y)
+{
+  /* hack, hack...  I look for the first LineDef crossing
+     an horizontal half-line drawn from the cursor */
+
+  /* RQ & BW have been very smart here. Their method works remarkably
+     well for normal sectors. However, self-referencing sectors are
+     frequently unclosed. If your SRS has only horizontal linedefs, this
+     method fails miserably. I suppose that the solution would be to look
+     for intersections in BOTH directions and pick the closest. Remind me
+     to look into it one of these days :-). -- AYM 1998-06-29 */
+
+  /* Initializing curx to 32767 instead of MapMaxX + 1. Fixes the old
+     DEU bug where sometimes you couldn't select a newly created sector
+     to the west of the level until you saved. (MapMaxX got out of date
+     and SaveLevelData() refreshed it.) -- AYM 1999-03-18 */
+  static Close_obj object;
+  int best_match = -1;
+  int curx = 32767;  // Oh yes, one more hard-coded constant!
+  ObjectsNeeded (OBJ_LINEDEFS, OBJ_VERTICES, 0);
+  for (int n = 0; n < NumLineDefs; n++)
+    if ((Vertices[LineDefs[n].start].y > y)
+     != (Vertices[LineDefs[n].end].y > y))
+    {
+      int lx0 = Vertices[LineDefs[n].start].x;
+      int ly0 = Vertices[LineDefs[n].start].y;
+      int lx1 = Vertices[LineDefs[n].end].x;
+      int ly1 = Vertices[LineDefs[n].end].y;
+      int m = lx0 + (int) ((long) (y - ly0) * (long) (lx1 - lx0)
+					    / (long) (ly1 - ly0));
+      if (m >= x && m < curx)
+      {
+	curx = m;
+	best_match = n;
+      }
+    }
+
+  // Now look if this linedef has a sidedef bound to one sector
+  object.nil ();
+  if (best_match >= 0)
+  {
+    if (Vertices[LineDefs[best_match].start].y
+      > Vertices[LineDefs[best_match].end].y)
+      best_match = LineDefs[best_match].sidedef1;
+    else
+      best_match = LineDefs[best_match].sidedef2;
+    if (best_match >= 0)
+    {
+      ObjectsNeeded (OBJ_SIDEDEFS, 0);
+      object.obj.type = OBJ_SECTORS;
+      object.obj.num  = SideDefs[best_match].sector;
+      object.distance = 0;	// Not meaningful for sectors
+      object.radius   = 1;	// Not meaningful for sectors
+      object.inside   = true;	// Not meaningful for sectors
+    }
+    else
+      ;
+  }
+  else
+    ;
+  return object;
+}
+
+
+/*
+ *	get_cur_thing - determine which thing is under the pointer
+ */
+static const Close_obj& get_cur_thing (int x, int y)
+{
+  static Close_obj closest;
+  const int screenslack = 15;			// Slack in pixels
+  double mapslack = fabs (screenslack / Scale);	// Slack in map units
+  int max_radius = (int) (get_max_thing_radius () + mapslack);
+  int xmin = x - max_radius;
+  int xmax = x + max_radius;
+  int ymin = y - max_radius;
+  int ymax = y + max_radius;
+
+  ObjectsNeeded (OBJ_THINGS, 0);
+  closest.nil ();
+  for (int n = 0; n < NumThings; n++)
+  {
+    // Filter out things that are farther than <max_radius> units away.
+    if (Things[n].xpos < xmin
+     || Things[n].xpos > xmax
+     || Things[n].ypos < ymin
+     || Things[n].ypos > ymax)
+       continue;
+
+    // So how far is that thing exactly ?
+#ifdef ROUND_THINGS
+    double dist = hypot (x - Things[n].xpos, y - Things[n].ypos);
+    if (dist < closest.distance
+     && dist <= get_thing_radius (Things[n].type) + mapslack)
+    {
+      closest.obj.type = OBJ_THINGS;
+      closest.obj.num  = n;
+      closest.distance = dist;
+      closest.radius   = get_thing_radius (Things[n].type);
+      closest.inside   = dist < closest.radius;
+    }
+#else
+    {
+      int thing_radius = (int) (get_thing_radius (Things[n].type) + mapslack);
+      if (x > Things[n].xpos - thing_radius
+       && x < Things[n].xpos + thing_radius
+       && y > Things[n].ypos - thing_radius
+       && y < Things[n].ypos + thing_radius)
+      {
+	Close_obj current;
+	current.obj.type = OBJ_THINGS;
+	current.obj.num  = n;
+	current.distance = hypot (x - Things[n].xpos, y - Things[n].ypos);
+	current.radius   = get_thing_radius (Things[n].type);
+	current.inside   = x > Things[n].xpos - current.radius
+			&& x < Things[n].xpos + current.radius
+			&& y > Things[n].ypos - current.radius
+			&& y < Things[n].ypos + current.radius;
+       if (current <= closest)  /* "<=" because if there are superimposed
+				   things, we want to return the
+				   highest-numbered one. */
+	  closest = current;
+      }
+    }
+#endif
+  }
+  return closest;
+}
+
+
+/*
+ *	get_cur_vertex - determine which vertex is under the pointer
+ */
+static const Close_obj& get_cur_vertex (int x, int y)
+{
+  static Close_obj object;
+  const int screenradius = vertex_radius (Scale);	// Radius in pixels
+  const int screenslack  = screenradius + 15;		// Slack in pixels
+  double    mapslack     = fabs (screenslack / Scale);	// Slack in map units
+  const int mapradius    = (int) (screenradius / Scale);// Radius in map units
+  int xmin = (int) (x - mapslack + 0.5);
+  int xmax = (int) (x + mapslack + 0.5);
+  int ymin = (int) (y - mapslack + 0.5);
+  int ymax = (int) (y + mapslack + 0.5);
+
+  ObjectsNeeded (OBJ_VERTICES, 0);
+  object.nil ();
+  for (int n = 0; n < NumVertices; n++)
+  {
+    /* Filter out objects that are farther than <radius> units away. */
+    if (Vertices[n].x < xmin
+     || Vertices[n].x > xmax
+     || Vertices[n].y < ymin
+     || Vertices[n].y > ymax)
+       continue;
+    double dist = hypot (x - Vertices[n].x, y - Vertices[n].y);
+    if (dist <= object.distance  /* "<=" because if there are superimposed
+				   vertices, we want to return the
+				   highest-numbered one. */
+       && dist <= mapslack)
+    {
+      object.obj.type = OBJ_VERTICES;
+      object.obj.num  = n;
+      object.distance = dist;
+      object.radius   = mapradius;
+      object.inside   = x > Vertices[n].x - mapradius
+		     && x < Vertices[n].x + mapradius
+		     && y > Vertices[n].y - mapradius
+		     && y < Vertices[n].y + mapradius;
+    }
+  }
+  return object;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/x_hover.h	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,17 @@
+/*
+ *	x_hover.h
+ *	AYM 2000-11-08
+ */
+
+
+#ifndef YH_X_HOVER  /* DO NOT INSERT ANYTHING BEFORE THIS LINE */
+#define YH_X_HOVER
+
+
+class Objid;
+
+
+void GetCurObject (Objid& o, int objtype, int x, int y);
+
+
+#endif  /* DO NOT ADD ANYTHING AFTER THIS LINE */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/x_mirror.cc	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,177 @@
+/*
+ *	x_mirror.cc
+ *	Flip or mirror objects
+ *	AYM 1999-05-01
+ */
+
+
+/*
+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 "bitvec.h"
+#include "l_vertices.h"
+#include "levels.h"
+#include "objid.h"
+#include "s_vertices.h"
+#include "selectn.h"
+#include "t_centre.h"
+#include "v_centre.h"
+#include "x_mirror.h"
+
+
+/*
+ *	flip_mirror
+ *	All objects of type <obj_type> in list <list> are
+ *	flipped (if <flags> is equal to 'f') or mirrored (if
+ *	<flags> is equal to 'm') around their geometric centre.
+ *
+ *	In addition of being moved, things have their angle
+ *	changed so as to remain consistent with their
+ *	environment (E.G. when mirroring or flipping the level
+ *	too).
+ */
+void flip_mirror (SelPtr list, int obj_type, char op)
+{
+  enum { flip, mirror } operation;
+  
+  if (op == 'f')
+    operation = flip;
+  else if (op == 'm')
+    operation = mirror;
+  else
+  {
+    nf_bug ("flip_mirror: Bad operation %02Xh", op);
+    return;
+  }
+
+  if (! list)
+    return;
+
+  /* Vertices, linedefs and sectors:
+     flip/mirror the vertices. */
+  if (obj_type == OBJ_VERTICES 
+      || obj_type == OBJ_LINEDEFS
+      || obj_type == OBJ_SECTORS)
+  {
+    // Get the list of vertices to flip/mirror.
+    bitvec_c *vert;
+    if (obj_type == OBJ_LINEDEFS)
+      vert = bv_vertices_of_linedefs (list);
+    else if (obj_type == OBJ_SECTORS)
+      vert = bv_vertices_of_sectors (list);
+    else
+      vert = list_to_bitvec (list, NumVertices);
+
+    /* Determine the geometric centre
+       of that set of vertices. */
+    int xref, yref;
+    centre_of_vertices (*vert, xref, yref);
+    xref *= 2;
+    yref *= 2;
+    
+    /* Change the coordinates of the
+       vertices. */
+    if (operation == flip)
+    {
+      int n;
+      VPtr v;
+      for (n = 0, v = Vertices; n < NumVertices; n++, v++)
+	if (vert->get (n))
+	  v->y = yref - v->y;
+    }
+    else if (operation == mirror)
+    {
+      int n;
+      VPtr v;
+      for (n = 0, v = Vertices; n < NumVertices; n++, v++)
+	if (vert->get (n))
+	  v->x = xref - v->x;
+    }
+      
+    /* Flip all the linedefs between the
+       flipped/mirrored vertices by swapping
+       their start and end vertices. */
+    {
+      int n;
+      LDPtr l;
+      for (n = 0, l = LineDefs; n < NumLineDefs; n++, l++)
+	if (vert->get (l->start) && vert->get (l->end))
+	{
+	  int w = l->start;
+	  l->start = l->end;
+	  l->end = w;
+	  MadeMapChanges = 1;
+	}
+    }
+    
+    delete vert;
+  }
+
+  /* Things: flip/mirror the things. */
+  else if (obj_type == OBJ_THINGS)
+  {
+    /* Determine the geometric centre
+       of that set of things. */
+    int xref, yref;
+    centre_of_things (list, &xref, &yref);
+    xref *= 2;
+    yref *= 2;
+
+    /* Change the coordinates of the
+       things and adjust the angles. */
+    if (operation == flip)
+    {
+      if (list)
+      {
+	things_angles++;
+	MadeChanges = 1;
+      }
+      for (SelPtr cur = list; cur; cur = cur->next)
+      {
+	TPtr t = Things + cur->objnum;
+	t->ypos = yref - t->ypos;
+	if (t->angle != 0)
+	  t->angle = 360 - t->angle;
+      }
+    }
+    else if (operation == mirror)
+    {
+      if (list)
+      {
+	things_angles++;
+	MadeChanges = 1;
+      }
+      for (SelPtr cur = list; cur; cur = cur->next)
+      {
+	TPtr t = Things + cur->objnum;
+	t->xpos = xref - t->xpos;
+	if (t->angle > 180)
+	  t->angle = 540 - t->angle;
+	else
+	  t->angle = 180 - t->angle;
+      }
+    }
+  }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/x_mirror.h	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,10 @@
+/*
+ *	x_mirror.h
+ *	Flip or mirror objects
+ *	AYM 1999-05-01
+ */
+
+
+void flip_mirror (SelPtr list, int obj_type, char op);
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/x_rotate.cc	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,119 @@
+/*
+ *	x_rotate.cc
+ *	Rotate and scale a group of objects
+ *	AYM 1998-02-07
+ */
+
+
+/*
+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 <math.h>
+#include "l_vertices.h"
+#include "levels.h"
+#include "objid.h"
+#include "s_vertices.h"
+#include "selectn.h"
+#include "t_centre.h"
+#include "v_centre.h"
+#include "x_rotate.h"
+
+
+/*
+   move (x, y) to a new position: rotate and scale around (0, 0)
+*/
+
+#if 0
+inline void RotateAndScaleCoords (int *x, int *y, double angle, double scale)
+{
+  double r, theta;
+
+  r = hypot ((double) *x, (double) *y);
+  theta = atan2 ((double) *y, (double) *x);
+  *x = (int) (r * scale * cos (theta + angle) + 0.5);
+  *y = (int) (r * scale * sin (theta + angle) + 0.5);
+}
+#endif
+
+
+/*
+   rotate and scale a group of objects around the centre of gravity
+*/
+
+void RotateAndScaleObjects (int objtype, SelPtr obj, double angle, double scale) /* SWAP! */
+{
+  int    dx, dy;
+  int    centerx, centery;
+  SelPtr cur, vertices;
+
+  if (obj == NULL)
+    return;
+  ObjectsNeeded (objtype, 0);
+
+  switch (objtype)
+  {
+    case OBJ_THINGS:
+      centre_of_things (obj, &centerx, &centery);
+      for (cur = obj; cur; cur = cur->next)
+	 {
+	 dx = Things[cur->objnum].xpos - centerx;
+	 dy = Things[cur->objnum].ypos - centery;
+	 RotateAndScaleCoords (&dx, &dy, angle, scale);
+	 Things[cur->objnum].xpos = centerx + dx;
+	 Things[cur->objnum].ypos = centery + dy;
+	 }
+      MadeChanges = 1;
+      break;
+
+    case OBJ_VERTICES:
+      centre_of_vertices (obj, &centerx, &centery);
+      for (cur = obj; cur; cur = cur->next)
+	 {
+	 dx = Vertices[cur->objnum].x - centerx;
+	 dy = Vertices[cur->objnum].y - centery;
+	 RotateAndScaleCoords (&dx, &dy, angle, scale);
+	 Vertices[cur->objnum].x = (centerx + dx + /*4*/ 2) & ~/*7*/3;
+	 Vertices[cur->objnum].y = (centery + dy + /*4*/ 2) & ~/*7*/3;
+	 }
+      MadeChanges = 1;
+      MadeMapChanges = 1;
+      break;
+
+    case OBJ_LINEDEFS:
+      vertices = list_vertices_of_linedefs (obj);
+      RotateAndScaleObjects (OBJ_VERTICES, vertices, angle, scale);
+      ForgetSelection (&vertices);
+      break;
+
+    case OBJ_SECTORS:
+      ObjectsNeeded (OBJ_LINEDEFS, OBJ_SIDEDEFS, 0);
+      vertices = list_vertices_of_sectors (obj);
+      RotateAndScaleObjects (OBJ_VERTICES, vertices, angle, scale);
+      ForgetSelection (&vertices);
+      break;
+  }
+}
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/x_rotate.h	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,44 @@
+/*
+ *	x_rotate.h
+ *	AYM 1998-11-22
+ */
+
+
+/*
+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 <math.h>
+
+
+inline void RotateAndScaleCoords (int *x, int *y, double angle, double scale)
+{
+  double r, theta;
+
+  r = hypot ((double) *x, (double) *y);
+  theta = atan2 ((double) *y, (double) *x);
+  *x = (int) (r * scale * cos (theta + angle) + 0.5);
+  *y = (int) (r * scale * sin (theta + angle) + 0.5);
+}
+
+void RotateAndScaleObjects (int, SelPtr, double, double);
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/xref.cc	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,133 @@
+/*
+ *	xref.cc
+ *	Cross reference stuff (who references who ?)
+ *	and miscellaneous test/debug/exploration funcs.
+ *	AYM 1999-03-31
+ */
+
+
+/*
+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 "levels.h"
+#include "selectn.h"
+
+
+void xref_sidedef ()
+{
+  int sidedef_no;
+  printf ("Enter sidedef number : ");
+  scanf ("%d", &sidedef_no);
+  printf ("Sidedef %d is used by linedefs:", sidedef_no);
+  int count = 0;
+  for (int n = 0; n < NumLineDefs; n++)
+  {
+    if (LineDefs[n].sidedef1 == sidedef_no)
+    {
+      printf (" %dR", n);
+      count++;
+    }
+    if (LineDefs[n].sidedef2 == sidedef_no)
+    {
+      printf (" %dL", n);
+      count++;
+    }
+  }
+  printf (" (total %d linedefs)\n", count);
+}
+
+
+void secret_sectors ()
+{
+  printf ("Secret sectors:");
+  int count = 0;
+  for (int n = 0; n < NumSectors; n++)
+    if (Sectors[n].special ==  9)  // FIXME hard-coded
+    {
+      printf (" %d", n);
+      count++;
+    }
+  printf (" (total %d)\n", count);
+
+}
+
+
+void unknown_linedef_type (SelPtr *list)
+{
+  for (int n = 0; n < NumLineDefs; n++)
+    if (*GetLineDefTypeName (LineDefs[n].type) == '?')
+      SelectObject (list, n);
+}
+
+
+void bad_sector_number (SelPtr *list)
+{
+  for (int n = 0; n < NumLineDefs; n++)
+  {
+    int s1 = LineDefs[n].sidedef1;
+    int s2 = LineDefs[n].sidedef2;
+    if (s1 >= 0 && s1 < NumSideDefs
+	&& SideDefs[s1].sector < 0 || SideDefs[s1].sector >= NumSectors
+     || s2 >= 0 && s2 < NumSideDefs
+        && SideDefs[s2].sector < 0 || SideDefs[s2].sector >= NumSectors)
+      SelectObject (list, n);
+  }
+}
+
+
+/*
+ *	A stopgap to please IvL
+ */
+void list_tagged_sectors (int tag)
+{
+  printf ("tag %d:", tag);
+  int count = 0;
+
+  for (int n = 0; n < NumSectors; n++)
+    if (Sectors[n].tag == tag)
+    {
+      printf (" %d", n);
+      count++;
+    }
+  printf (" (total %d)\n", count);
+}
+
+
+/*
+ *	A stopgap to please IvL
+ */
+void list_tagged_linedefs (int tag)
+{
+  printf ("tag %d:", tag);
+  int count = 0;
+
+  for (int n = 0; n < NumLineDefs; n++)
+    if (LineDefs[n].tag == tag)
+    {
+      printf (" %d", n);
+      count++;
+    }
+  printf (" (total %d)\n", count);
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/xref.h	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,16 @@
+/*
+ *	xref.cc
+ *	Cross reference stuff (who references who ?)
+ *	and miscellaneous test/debug/exploration funcs.
+ *	AYM 1999-03-31
+ */
+
+
+void xref_sidedef ();
+void secret_sectors ();
+void unknown_linedef_type (SelPtr *list);
+void bad_sector_number (SelPtr *list);
+void list_tagged_sectors (int tag);
+void list_tagged_linedefs (int tag);
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/yadex.cc	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,1387 @@
+/*
+ *	yadex.cc
+ *	The main module.
+ *	BW & RQ sometime in 1993 or 1994.
+ */
+
+
+/*
+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 <time.h>
+#include "acolours.h"
+#include "bench.h"
+#include "cfgfile.h"
+#include "disppic.h"  /* Because of "p" */
+#include "editlev.h"
+#include "endian.h"
+#include "flats.h"
+#include "game.h"
+#include "gfx.h"
+#include "gfx2.h"
+#include "help1.h"
+#include "levels.h"    /* Because of "viewtex" */
+#include "lists.h"
+#include "mkpalette.h"
+#include "palview.h"
+#include "patchdir.h"  /* Because of "p" */
+#include "rgb.h"
+#include "sanity.h"
+#include "textures.h"
+#include "x11.h"
+#include "wadfile.h"
+#include "wadlist.h"
+#include "wadname.h"
+#include "wadres.h"
+#include "wads2.h"
+
+
+/*
+ *	Constants (declared in yadex.h)
+ */
+const char *const log_file       = "yadex.log";
+const char *const msg_unexpected = "unexpected error";
+const char *const msg_nomem      = "Not enough memory";
+
+
+/*
+ *	Not real variables -- just unique pointer values
+ *	used by functions that return pointers to 
+ */
+char error_non_unique[1];  // Found more than one
+char error_none[1];        // Found none
+char error_invalid[1];     // Invalid parameter
+
+
+/*
+ *	Global variables
+ */
+const char *install_dir = 0;		// Where Yadex is installed
+FILE *      logfile     = NULL;		// Filepointer to the error log
+bool        Registered  = false;	// Registered or shareware game?
+int         screen_lines = 24;  	// Lines that our TTY can display
+int         remind_to_build_nodes = 0;	// Remind user to build nodes
+Wad_res     wad_res (&MasterDir);
+
+// Set from command line and/or config file
+bool      autoscroll			= 0;
+unsigned long autoscroll_amp		= 10;
+unsigned long autoscroll_edge		= 30;
+const char *config_file                 = NULL;
+int       copy_linedef_reuse_sidedefs	= 0;
+int       cpu_big_endian		= 0;
+bool      Debug				= false;
+int       default_ceiling_height	= 128;
+char      default_ceiling_texture[WAD_FLAT_NAME + 1]	= "CEIL3_5";
+int       default_floor_height				= 0;
+char      default_floor_texture[WAD_FLAT_NAME + 1]	= "FLOOR4_8";
+int       default_light_level				= 144;
+char      default_lower_texture[WAD_TEX_NAME + 1]	= "STARTAN3";
+char      default_middle_texture[WAD_TEX_NAME + 1]	= "STARTAN3";
+char      default_upper_texture[WAD_TEX_NAME + 1]	= "STARTAN3";
+int       default_thing			= 3004;
+int       double_click_timeout		= 200;
+bool      Expert			= false;
+const char *Game			= NULL;
+int       grid_pixels_min		= 10;
+int       GridMin			= 2;
+int       GridMax			= 128;
+int       idle_sleep_ms			= 50;
+bool      InfoShown			= true;
+int       zoom_default			= 0;  // 0 means fit
+int       zoom_step			= 0;  // 0 means sqrt(2)
+int       digit_zoom_base               = 100;
+int       digit_zoom_step               = 0;  // 0 means sqrt(2)
+confirm_t insert_vertex_split_linedef	= YC_ASK_ONCE;
+confirm_t insert_vertex_merge_vertices	= YC_ASK_ONCE;
+bool      blindly_swap_sidedefs         = false;
+const char *Iwad1			= NULL;
+const char *Iwad2			= NULL;
+const char *Iwad3			= NULL;
+const char *Iwad4			= NULL;
+const char *Iwad5			= NULL;
+const char *Iwad6			= NULL;
+const char *Iwad7			= NULL;
+const char *Iwad8			= NULL;
+const char *Iwad9			= NULL;
+const char *Iwad10			= NULL;
+const char *MainWad			= NULL;
+#ifdef AYM_MOUSE_HACKS
+int       MouseMickeysH			= 5;
+int       MouseMickeysV			= 5;
+#endif
+char **   PatchWads			= NULL;
+bool      Quiet				= false;
+bool      Quieter			= false;
+unsigned long scroll_less		= 10;
+unsigned long scroll_more		= 90;
+bool      Select0			= false;
+int       show_help			= 0;
+int       sprite_scale                  = 100;
+bool      SwapButtons			= false;
+int       verbose			= 0;
+int       welcome_message		= 1;
+const char *bench			= 0;
+
+// Global variables declared in game.h
+yglf_t yg_level_format   = YGLF__;
+ygln_t yg_level_name     = YGLN__;
+ygpf_t yg_picture_format = YGPF_NORMAL;
+ygtf_t yg_texture_format = YGTF_NORMAL;
+ygtl_t yg_texture_lumps  = YGTL_NORMAL;
+al_llist_t *ldtdef       = NULL;
+al_llist_t *ldtgroup     = NULL;
+al_llist_t *stdef        = NULL;
+al_llist_t *thingdef     = NULL;
+al_llist_t *thinggroup   = NULL;
+Wad_name sky_flat;
+
+
+/*
+ *	Prototypes of private functions
+ */
+static int  parse_environment_vars ();
+static void MainLoop ();
+static void print_error_message (const char *fmt, va_list args);
+static void add_base_colours ();
+static const Wad_file *wad_by_name (const char *pathname);
+static bool wad_already_loaded (const char *pathname);
+
+
+/*
+ *	main
+ *	Guess what.
+ */
+int main (int argc, char *argv[])
+{
+int r;
+
+// Set <screen_lines>
+if (getenv ("LINES") != NULL)
+   screen_lines = atoi (getenv ("LINES"));
+else
+   screen_lines = 0;
+if (screen_lines == 0)
+   screen_lines = 24;
+
+// InitSwap must be called before any call to GetMemory(), etc.
+InitSwap ();
+
+// First detect manually --help and --version
+// because parse_command_line_options() cannot.
+if (argc == 2 && strcmp (argv[1], "--help") == 0)
+   {
+   print_usage (stdout);
+   if (fflush (stdout) != 0)
+     fatal_error ("stdout: %s", strerror (errno));
+   exit (0);
+   }
+if (argc == 2 && strcmp (argv[1], "--version") == 0)
+   {
+   puts (what ());
+   puts (config_file_magic);
+   puts (ygd_file_magic);
+   if (fflush (stdout) != 0)
+     fatal_error ("stdout: %s", strerror (errno));
+   exit (0);
+   }
+
+// Second a quick pass through the command line
+// arguments to detect -?, -f and -help.
+r = parse_command_line_options (argc - 1, argv + 1, 1);
+if (r)
+   goto syntax_error;
+
+if (show_help)
+   {
+   print_usage (stdout);
+   exit (1);
+   }
+
+printf ("%s\n", what ());
+
+// Where am I installed ? (the config file might be there)
+#if defined Y_DOS
+install_dir = spec_path (argv[0]);
+#endif
+
+// The config file provides some values.
+if (config_file != NULL)
+  r = parse_config_file_user (config_file);
+else
+  r = parse_config_file_default ();
+if (r == 0)
+   {
+   // Environment variables can override them.
+   r = parse_environment_vars ();
+   if (r == 0)
+      {
+      // And the command line argument can override both.
+      r = parse_command_line_options (argc - 1, argv + 1, 2);
+      }
+   }
+if (r != 0)
+   {
+   syntax_error :
+   fprintf (stderr, "Try \"yadex --help\" or \"man yadex\".\n");
+   exit (1);
+   }
+
+if (Game != NULL && strcmp (Game, "doom") == 0)
+   {
+   if (Iwad1 == NULL)
+      {
+      err ("You have to tell me where doom.wad is.");
+      fprintf (stderr,
+         "Use \"-i1 <file>\" or put \"iwad1=<file>\" in yadex.cfg.\n");
+      exit (1);
+      }
+   MainWad = Iwad1;
+   }
+else if (Game != NULL && strcmp (Game, "doom2") == 0)
+   {
+   if (Iwad2 == NULL)
+      {
+      err ("You have to tell me where doom2.wad is.");
+      fprintf (stderr,
+         "Use \"-i2 <file>\" or put \"iwad2=<file>\" in yadex.cfg.\n");
+      exit (1);
+      }
+   MainWad = Iwad2;
+   }
+else if (Game != NULL && strcmp (Game, "heretic") == 0)
+   {
+   if (Iwad3 == NULL)
+      {
+      err ("You have to tell me where heretic.wad is.");
+      fprintf (stderr,
+         "Use \"-i3 <file>\" or put \"iwad3=<file>\" in yadex.cfg.\n");
+      exit (1);
+      }
+   MainWad = Iwad3;
+   }
+else if (Game != NULL && strcmp (Game, "hexen") == 0)
+   {
+   if (Iwad4 == NULL)
+      {
+      err ("You have to tell me where hexen.wad is.");
+      fprintf (stderr,
+         "Use \"-i4 <file>\" or put \"iwad4=<file>\" in yadex.cfg.\n");
+      exit (1);
+      }
+   MainWad = Iwad4;
+   }
+else if (Game != NULL && strcmp (Game, "strife") == 0)
+   {
+   if (Iwad5 == NULL)
+      {
+      err ("You have to tell me where strife1.wad is.");
+      fprintf (stderr,
+         "Use \"-i5 <file>\" or put \"iwad5=<file>\" in yadex.cfg.\n");
+      exit (1);
+      }
+   MainWad = Iwad5;
+   }
+else if (Game != NULL && strcmp (Game, "doom02") == 0)
+   {
+   if (Iwad6 == NULL)
+      {
+      err ("You have to tell me where the Doom alpha 0.2 iwad is.");
+      fprintf (stderr,
+         "Use \"-i6 <file>\" or put \"iwad6=<file>\" in yadex.cfg.\n");
+      exit (1);
+      }
+   MainWad = Iwad6;
+   }
+else if (Game != NULL && strcmp (Game, "doom04") == 0)
+   {
+   if (Iwad7 == NULL)
+      {
+      err ("You have to tell me where the Doom alpha 0.4 iwad is.");
+      fprintf (stderr,
+         "Use \"-i7 <file>\" or put \"iwad7=<file>\" in yadex.cfg.\n");
+      exit (1);
+      }
+   MainWad = Iwad7;
+   }
+else if (Game != NULL && strcmp (Game, "doom05") == 0)
+   {
+   if (Iwad8 == NULL)
+      {
+      err ("You have to tell me where the Doom alpha 0.5 iwad is.");
+      fprintf (stderr,
+         "Use \"-i8 <file>\" or put \"iwad8=<file>\" in yadex.cfg.\n");
+      exit (1);
+      }
+   MainWad = Iwad8;
+   }
+else if (Game != NULL && strcmp (Game, "doompr") == 0)
+   {
+   if (Iwad9 == NULL)
+      {
+      err ("You have to tell me where the Doom press release iwad is.");
+      fprintf (stderr,
+         "Use \"-i9 <file>\" or put \"iwad9=<file>\" in yadex.cfg.\n");
+      exit (1);
+      }
+   MainWad = Iwad9;
+   }
+else if (Game != NULL && strcmp (Game, "strife10") == 0)
+   {
+   if (Iwad10 == NULL)
+      {
+      err ("You have to tell me where strife1.wad is.");
+      fprintf (stderr,
+         "Use \"-i10 <file>\" or put \"iwad10=<file>\" in yadex.cfg.\n");
+      exit (1);
+      }
+   MainWad = Iwad10;
+   }
+else
+   {
+   if (Game == NULL)
+      err ("You didn't say for which game you want to edit.");
+   else
+      err ("Unknown game \"%s\"", Game);
+   fprintf (stderr,
+  "Use \"-g <game>\" on the command line or put \"game=<game>\" in yadex.cfg\n"
+  "where <game> is one of \"doom\", \"doom02\", \"doom04\", \"doom05\","
+  " \"doom2\",\n\"doompr\", \"heretic\", \"hexen\", \"strife\" and "
+  "\"strife10\".\n");
+   exit (1);
+   }
+if (Debug)
+   {
+   logfile = fopen (log_file, "a");
+   if (logfile == NULL)
+      warn ("can't open log file \"%s\" (%s)", log_file, strerror (errno));
+   LogMessage (": Welcome to Yadex!\n");
+   }
+if (Quieter)
+   Quiet = true;
+
+// Sanity checks (useful when porting).
+check_types ();
+check_charset ();
+
+// Misc. things done only once.
+cpu_big_endian = native_endianness ();
+add_base_colours ();
+
+// Load game definitions (*.ygd).
+InitGameDefs ();
+LoadGameDefs (Game);
+
+// Load the iwad and the pwads.
+if (OpenMainWad (MainWad))
+   fatal_error ("If you don't give me an iwad, I'll quit. I'm serious.");
+if (PatchWads)
+   {
+   const char * const *pwad_name;
+   for (pwad_name = PatchWads; *pwad_name; pwad_name++)
+      OpenPatchWad (*pwad_name);
+   }
+/* sanity check */
+CloseUnusedWadFiles ();
+
+// BRANCH 1 : benchmarking (-b)
+if (bench != 0)
+   {
+   benchmark (bench);
+   return 0;  // Exit successfully
+   }
+
+// BRANCH 2 : normal use ("yadex:" prompt)
+else
+   {
+   if (welcome_message)
+      print_welcome (stdout);
+
+   if (strcmp (Game, "hexen") == 0)
+      printf (
+   "WARNING: Hexen mode is experimental. Don't expect to be able to do any\n"
+   "real Hexen editing with it. You can edit levels but you can't save them.\n"
+   "And there might be other bugs... BE CAREFUL !\n\n");
+
+   if (strcmp (Game, "strife") == 0)
+      printf (
+   "WARNING: Strife mode is experimental. Many thing types, linedef types,\n"
+   "etc. are missing or wrong. And be careful, there might be bugs.\n\n");
+
+   /* all systems go! */
+   MainLoop ();
+   }
+
+/* that's all, folks! */
+CloseWadFiles ();
+FreeGameDefs ();
+LogMessage (": The end!\n\n\n");
+if (logfile != NULL)
+   fclose (logfile);
+if (remind_to_build_nodes)
+   printf ("\n"
+      "** You have made changes to one or more wads. Don't forget to pass\n"
+      "** them through a nodes builder (E.G. BSP) before running them.\n"
+      "** Like this: \"ybsp foo.wad -o tmp.wad; doom -file tmp.wad\"\n\n");
+return 0;
+}
+
+
+/*
+ *	parse_environment_vars
+ *	Check certain environment variables.
+ *	Returns 0 on success, <>0 on error.
+ */
+static int parse_environment_vars ()
+{
+char *value;
+
+value = getenv ("YADEX_GAME");
+if (value != NULL)
+   Game = value;
+return 0;
+}
+
+
+/*
+   play a fascinating tune
+*/
+
+void Beep ()
+{
+#if defined Y_DOS
+if (! Quieter)
+   {
+   sound (640);
+   delay (100);
+   nosound ();
+   }
+#elif defined Y_UNIX
+if (! Quieter)
+#if 0
+   if (dpy)  // FIXME not defined here !
+#else
+   if (1)
+#endif
+      x_bell ();
+   else
+   {
+      putchar ('\a');
+      fflush (stdout);
+   }
+#endif
+}
+
+
+
+/*
+   play a sound
+*/
+
+void PlaySound (int freq, int msec)
+{
+#if defined Y_DOS
+if (! Quiet)
+   {
+   sound (freq);
+   delay (msec);
+   nosound ();
+   }
+#elif defined Y_UNIX
+freq = msec;	// To prevent a warning about unused variables
+return;
+#endif
+}
+
+
+
+/*
+ *	fatal_error
+ *	Print an error message and terminate the program with code 2.
+ */
+void fatal_error (const char *fmt, ...)
+{
+// With BGI, we have to switch back to text mode
+// before printing the error message so do it now...
+#ifdef Y_BGI
+if (GfxMode)
+   {
+   sleep (1);
+   TermGfx ();
+   }
+#endif
+
+va_list args;
+va_start (args, fmt);
+print_error_message (fmt, args);
+
+// ... on the other hand, with X, we don't have to
+// call TermGfx() before printing so we do it last so
+// that a segfault occuring in TermGfx() does not
+// prevent us from seeing the stderr message.
+#ifdef Y_X11
+if (GfxMode)
+   TermGfx ();  // Don't need to sleep (1) either.
+#endif
+
+// Clean up things and free swap space
+ForgetLevelData ();
+ForgetWTextureNames ();
+ForgetFTextureNames ();
+CloseWadFiles ();
+exit (2);
+}
+
+
+/*
+ *	err
+ *	Print an error message but do not terminate the program.
+ */
+void err (const char *fmt, ...)
+{
+va_list args;
+
+va_start (args, fmt);
+print_error_message (fmt, args);
+}
+
+
+/*
+ *	print_error_message
+ *	Print an error message to stderr.
+ */
+static void print_error_message (const char *fmt, va_list args)
+{
+fflush (stdout);
+fputs ("Error: ", stderr);
+vfprintf (stderr, fmt, args);
+fputc ('\n', stderr);
+fflush (stderr);
+if (Debug && logfile != NULL)
+   {
+   fputs ("Error: ", logfile);
+   vfprintf (logfile, fmt, args);
+   fputc ('\n', logfile);
+   fflush (logfile);
+   }
+}
+
+
+/*
+ *	nf_bug
+ *	Report about a non-fatal bug to stderr. The message
+ *	should not expand to more than 80 characters.
+ */
+void nf_bug (const char *fmt, ...)
+{
+static bool first_time = 1;
+static int repeats = 0;
+static char msg_prev[81];
+char msg[81];
+
+va_list args;
+va_start (args, fmt);
+y_vsnprintf (msg, sizeof msg, fmt, args);
+if (first_time || strncmp (msg, msg_prev, sizeof msg))
+   {
+   fflush (stdout);
+   if (repeats)
+      {
+      fprintf (stderr, "Bug: Previous message repeated %d times\n",
+	    repeats);
+      repeats = 0;
+      }
+
+   fprintf (stderr, "Bug: %s\n", msg);
+   fflush (stderr);
+   if (first_time)
+      {
+      fputs ("REPORT ALL \"Bug:\" MESSAGES TO THE MAINTAINER !\n", stderr);
+      first_time = 0;
+      }
+   strncpy (msg_prev, msg, sizeof msg_prev);
+   }
+else
+   {
+   repeats++;  // Same message as above
+   if (repeats == 10)
+      {
+      fflush (stdout);
+      fprintf (stderr, "Bug: Previous message repeated %d times\n",
+	    repeats);
+      fflush (stderr);
+      repeats = 0;
+      }
+   }
+}
+
+
+/*
+   write a message in the log file
+*/
+
+void LogMessage (const char *logstr, ...)
+{
+va_list  args;
+time_t   tval;
+char    *tstr;
+
+if (Debug && logfile != NULL)
+   {
+   va_start (args, logstr);
+   /* if the message begins with ":", output the current date & time first */
+   if (logstr[0] == ':')
+      {
+      time (&tval);
+      tstr = ctime (&tval);
+      tstr[strlen (tstr) - 1] = '\0';
+      fprintf (logfile, "%s", tstr);
+      }
+   vfprintf (logfile, logstr, args);
+   fflush (logfile);  /* AYM 19971031 */
+   }
+}
+
+
+
+/*
+   the main program menu loop
+*/
+
+static void MainLoop ()
+{
+char input[120];
+char *com, *out;
+FILE *file, *raw;
+
+for (;;)
+   {
+   /* get the input */
+   printf ("yadex: ");
+   if (! fgets (input, sizeof input, stdin))
+      {
+      puts ("q");
+      break;
+      }
+
+   /* Strip the trailing '\n' */
+   if (strlen (input) > 0 && input[strlen (input) - 1] == '\n')
+      input[strlen (input) - 1] = '\0';
+
+   /* eat the white space and get the first command word */
+   com = strtok (input, " ");
+
+   /* user just hit return */
+   if (com == NULL)
+      printf ("Please enter a command or ? for help.\n");
+
+   /* user inputting for help */
+   else if (strcmp (com, "?") == 0
+	 || strcmp (com, "h") == 0
+	 || strcmp (com, "help") == 0)
+      {
+      printf ("? | h | help                      --"
+              " display this text\n");
+      printf ("b[uild] <WadFile>                 --"
+              " build a new iwad\n");
+      printf ("c[reate] <levelname>              --"
+              " create and edit a new (empty) level\n");
+      printf ("d[ump] <DirEntry> [outfile]       --"
+              " dump a directory entry in hex\n");
+      printf ("e[dit] <levelname>                --"
+              " edit a game level saving results to\n");
+      printf ("                                          a patch wad file\n");
+      printf ("g[roup] <WadFile>                 --"
+              " group all patch wads in a file\n");
+      printf ("i[nsert] <RawFile> <DirEntry>     --"
+              " insert a raw file in a patch wad file\n");
+      printf ("l[ist] <WadFile> [outfile]        --"
+              " list the directory of a wadfile\n");
+      printf ("m[aster] [outfile]                --"
+              " list the master directory\n");
+      printf ("make_gimp_palette <outfile>       --"
+              " generate a gimp palette file from\n"
+              "                                    "
+              " entry 0 of lump PLAYPAL.\n");
+      printf ("make_palette_ppm <outfile>        --"
+              " generate a palette image from\n"
+              "                                    "
+              " entry 0 of lump PLAYPAL.\n");
+      printf ("q[uit]                            --"
+              " quit\n");
+      printf ("r[ead] <WadFile>                  --"
+              " read a new wad patch file\n");
+      printf ("s[ave] <DirEntry> <WadFile>       --"
+              " save one object to a separate file\n");
+      printf ("set                               --"
+              " list all options and their values\n");
+      printf ("v[iew] [<spritename>]             --"
+              " display the sprites\n");
+      printf ("viewflat [<flatname>]             --"
+	      " flat viewer\n");
+      printf ("viewpal                           --"
+	      " palette viewer\n");
+      printf ("viewpat [<patchname>]             --"
+	      " patch viewer\n");
+      printf ("viewtex [<texname>]               --"
+	      " texture viewer\n");
+      printf ("w[ads]                            --"
+              " display the open wads\n");
+      printf ("x[tract] <DirEntry> <RawFile>     --"
+              " save (extract) one object to a raw file\n");
+      }
+
+   /* user asked for list of open wad files */
+   else if (strcmp (com, "wads") == 0 || strcmp (com, "w") == 0)
+      {
+      const Wad_file *wf;
+      wad_list.rewind ();
+      if (wad_list.get (wf))
+	 printf ("%-40s  Iwad\n", wf->pathname ());
+      while (wad_list.get (wf))
+	 printf ("%-40s  Pwad (%.*s)\n",
+	    wf->pathname (), (int) WAD_NAME, wf->what ());
+      }
+
+   /* user asked to quit */
+   else if (strcmp (com, "quit") == 0 || strcmp (com, "q") == 0)
+      {
+      if (! Registered)
+	 printf ("Remember to register your copy of the game !\n");
+      break;
+      }
+
+   /* user asked to edit a level */
+   else if (strcmp (com, "edit") == 0 || strcmp (com, "e") == 0
+         || strcmp (com, "create") == 0 || strcmp (com, "c") == 0)
+      {
+      const int newlevel = strcmp (com, "create") == 0
+			|| strcmp (com, "c") == 0;
+      char *level_name = 0;
+      com = strtok (NULL, " ");
+      if (com == 0)
+	 if (! newlevel)
+	    {
+	    printf ("Which level ?\n");
+	    continue;
+	    }
+         else
+	    level_name = 0;
+      else
+	 {
+	 level_name = find_level (com);
+	 if (level_name == error_invalid)
+	    {
+	    printf ("\"%s\" is not a valid level name.\n", com);
+	    continue;
+	    }
+	 else if (level_name == error_none)
+	    {
+	    printf ("Neither E%dM%d nor MAP%02d exist.\n",
+	       atoi (com) / 10, atoi (com) % 10, atoi (com));
+	    continue;
+	    }
+	 else if (level_name == error_non_unique)
+	    {
+	    printf ("Both E%dM%d and MAP%02d exist. Use an unambiguous name.\n",
+	       atoi (com) / 10, atoi (com) % 10, atoi (com));
+	    continue;
+	    }
+	 else if (level_name == NULL)
+	    {
+	    printf ("Level %s not found.", com);
+	    // Hint absent-minded users
+	    if (tolower (*com) == 'e' && yg_level_name == YGLN_MAP01
+	       || tolower (*com) == 'm' && yg_level_name == YGLN_E1M1)
+	       printf (" You are in %s mode.", Game);
+	    else if (tolower (*com) == 'e' && com[1] > '1' && ! Registered)
+	       printf (" You have the shareware iwad.");
+	    putchar ('\n');
+	    continue;
+	    }
+	 }
+      EditLevel (level_name, newlevel);
+      if (level_name)
+         free (level_name);
+      }
+
+   /* user asked to build a new main wad file */
+   else if (strcmp (com, "build") == 0 || strcmp (com, "b") == 0)
+      {
+      com = strtok (NULL, " ");
+      if (com == NULL)
+	 {
+	 printf ("Wad file name argument missing.\n");
+	 continue;
+	 }
+      if (wad_already_loaded (com))
+	 {
+	 printf ("%s: in use, close it first\n", com);
+	 continue;
+	 }
+      BuildNewMainWad (com, 0);
+      }
+
+   /* user asked to build a compound patch wad file */
+   else if (strcmp (com, "group") == 0 || strcmp (com, "g") == 0)
+      {
+      wad_list.rewind ();
+      const Wad_file *wf;
+      if (! wad_list.get (wf) || ! wad_list.get (wf))
+	 {
+	 printf ("You need at least two open wad files "
+	   "if you want to group them.\n");
+	 continue;
+	 }
+      com = strtok (NULL, " ");
+      if (com == NULL)
+	 {
+	 printf ("Wad file name argument missing.\n");
+	 continue;
+	 }
+      if (wad_already_loaded (com))
+	 {
+	 printf ("%s: in use, close it first\n", com);
+	 continue;
+	 }
+      BuildNewMainWad (com, 1);
+      }
+
+   /* user ask for a listing of a wad file */
+   else if (strcmp (com, "list") == 0 || strcmp (com, "l") == 0)
+      {
+      com = strtok (NULL, " ");
+      if (com == NULL)
+	 {
+	 printf ("Wad file name argument missing.\n");
+	 continue;
+	 }
+      const Wad_file *wf = wad_by_name (com);
+      if (wf == 0)
+	 {
+	 printf ("%s: not open\n", com);
+	 continue;
+	 }
+      out = strtok (NULL, " ");
+      if (out)
+	 {
+	 printf ("Outputting directory of \"%s\" to \"%s\".\n",
+	   wf->pathname (), out);
+	 if ((file = fopen (out, "w")) == NULL)
+	    fatal_error ("error opening output file \"%s\"", com);
+	 fprintf (file, "%s\n", what ());
+	 ListFileDirectory (file, wf);
+	 fprintf (file, "\nEnd of file.\n");
+	 fclose (file);
+	 }
+      else
+	 ListFileDirectory (stdout, wf);
+      }
+
+   /* user asked for the list of the master directory */
+   else if (strcmp (com, "master") == 0 || strcmp (com, "m") == 0)
+      {
+      out = strtok (NULL, " ");
+      if (out)
+	 {
+	 printf ("Outputting master directory to \"%s\".\n", out);
+	 if ((file = fopen (out, "w")) == NULL)
+	    fatal_error ("error opening output file \"%s\"", com);
+	 fprintf (file, "%s\n", what ());
+	 ListMasterDirectory (file);
+	 fprintf (file, "\nEnd of file.\n");
+	 fclose (file);
+	 }
+      else
+	 ListMasterDirectory (stdout);
+      }
+
+   // make_gimp_palette
+   else if (strcmp (com, "make_gimp_palette") == 0)
+      {
+      out = strtok (NULL, " ");
+      if (out == NULL)
+         {
+         printf ("Output file name argument missing.\n");
+         continue;
+         }
+      make_gimp_palette (0, out);
+      }
+
+   // make_palette_ppm
+   else if (strcmp (com, "make_palette_ppm") == 0)
+      {
+      out = strtok (NULL, "");
+      if (out == NULL)
+	 {
+	 printf ("Output file name argument missing.\n");
+	 continue;
+	 }
+      make_palette_ppm (0, out);
+      }
+
+   // make_palette_ppm
+   else if (strcmp (com, "mp2") == 0)
+      {
+      out = strtok (NULL, "");
+      if (out == NULL)
+	 {
+	 printf ("Output file name argument missing.\n");
+	 continue;
+	 }
+      make_palette_ppm_2 (0, out);
+      }
+
+   /* user asked to list all options and their values */
+   else if (strcmp (com, "set") == 0)
+      {
+      dump_parameters (stdout);
+      }
+
+   /* user asked to read a new patch wad file */
+   else if (strcmp (com, "read") == 0 || strcmp (com, "r") == 0)
+      {
+      com = strtok (NULL, " ");
+      if (com == NULL)
+	 {
+	 printf ("Wad file name argument missing.\n");
+	 continue;
+	 }
+      out = strtok (NULL, " ");
+      if (out)
+	*out = '\0';
+      out = (char *) GetMemory (strlen (com) + 1);
+      strcpy (out, com);
+      OpenPatchWad (out);
+      CloseUnusedWadFiles ();
+      }
+
+   /* user asked to dump the contents of a wad file */
+   else if (strcmp (com, "dump") == 0 || strcmp (com, "d") == 0)
+      {
+      com = strtok (NULL, " ");
+      if (com == NULL)
+	 {
+	 printf ("Object name argument missing.\n");
+	 continue;
+	 }
+      out = strtok (NULL, " ");
+      if (out)
+	 {
+	 printf ("Outputting directory entry data to \"%s\".\n", out);
+	 if ((file = fopen (out, "w")) == NULL)
+	    fatal_error ("error opening output file \"%s\"", com);
+	 fprintf (file, "%s\n", what ());
+	 DumpDirectoryEntry (file, com);
+	 fprintf (file, "\nEnd of file.\n");
+	 fclose (file);
+	 }
+      else
+	 DumpDirectoryEntry (stdout, com);
+      }
+
+   // "v"/"view" - view the sprites
+   else if (strcmp (com, "view") == 0 || strcmp (com, "v") == 0)
+      {
+      if (InitGfx ())
+	 goto v_end;
+      init_input_status ();
+      do
+	 get_input_status ();
+      while (is.key != YE_EXPOSE);
+      force_window_not_pixmap ();  // FIXME quick hack
+      {
+      Lump_list list;
+      wad_res.sprites.list (list);
+      char buf[WAD_PIC_NAME + 1];
+      const char *sprite = strtok (NULL, " ");
+      *buf = '\0';
+      if (sprite != 0)
+      {
+	strncat (buf, sprite, sizeof buf - 1);
+	for (char *p = buf; *p != '\0'; p++)
+	  *p = toupper (*p);
+      }
+      InputNameFromListWithFunc (-1, -1, "Sprite viewer", list.size (),
+	list.data (), 10, buf, 320, 200, display_pic,
+	HOOK_DISP_SIZE | HOOK_SPRITE);
+      }
+      TermGfx ();
+      v_end:;
+      }
+
+   // "viewflat" - view the flats
+   else if (strcmp (com, "viewflat") == 0)
+      {
+      if (InitGfx ())
+	goto viewflat_end;
+      init_input_status ();
+      do
+	 get_input_status ();
+      while (is.key != YE_EXPOSE);
+      com = strtok (NULL, " ");
+      force_window_not_pixmap ();  // FIXME quick hack
+      char buf[WAD_FLAT_NAME + 1];
+      *buf = '\0';
+      if (com != 0)
+	strncat (buf, com, sizeof buf - 1);
+      ReadFTextureNames ();
+      {
+      char **flat_names =
+	(char **) GetMemory (NumFTexture * sizeof *flat_names);
+      for (size_t n = 0; n < NumFTexture; n++)
+	flat_names[n] = flat_list[n].name;
+      ChooseFloorTexture (-1, -1, "Flat viewer",
+	NumFTexture, flat_names, buf);
+      FreeMemory (flat_names);
+      }
+      ForgetFTextureNames ();
+      TermGfx ();
+      viewflat_end:;
+      }
+
+   // "viewpal" - view the palette (PLAYPAL and COLORMAP)
+   else if (strcmp (com, "viewpal") == 0)
+      {
+      if (InitGfx ())
+	goto viewpal_end;
+      init_input_status ();
+      do
+	 get_input_status ();
+      while (is.key != YE_EXPOSE);
+      force_window_not_pixmap ();  // FIXME quick hack
+      {
+      Palette_viewer pv;
+      pv.run ();
+      }
+      TermGfx ();
+      viewpal_end:;
+      }
+   
+   // "viewpat" - view the patches
+   else if (strcmp (com, "viewpat") == 0)
+      {
+      if (InitGfx ())
+	goto viewpat_end;
+      init_input_status ();
+      do
+	 get_input_status ();
+      while (is.key != YE_EXPOSE);
+      com = strtok (NULL, " ");
+      force_window_not_pixmap ();  // FIXME quick hack
+      patch_dir.refresh (MasterDir);
+      {
+	 char buf[WAD_NAME + 1];
+	 *buf = '\0';
+	 if (com != 0)
+	   strncat (buf, com, sizeof buf - 1);
+	 Patch_list pl;
+	 patch_dir.list (pl);
+	 InputNameFromListWithFunc (-1, -1, "Patch viewer", pl.size (),
+	       pl.data (), 10, buf, 256, 256, display_pic,
+	       HOOK_DISP_SIZE | HOOK_PATCH);
+      }
+      TermGfx ();
+      viewpat_end:;
+      }
+
+   // "viewtex" - view the textures
+   else if (strcmp (com, "viewtex") == 0)
+      {
+      if (InitGfx ())
+	goto viewtex_end;
+      init_input_status ();
+      do
+	 get_input_status ();
+      while (is.key != YE_EXPOSE);
+      com = strtok (NULL, " ");
+      force_window_not_pixmap ();  // FIXME quick hack
+      patch_dir.refresh (MasterDir);
+      {
+	 char buf[WAD_TEX_NAME + 1];
+	 *buf = '\0';
+	 if (com != 0)
+	   strncat (buf, com, sizeof buf - 1);
+	 ReadWTextureNames ();
+	 ChooseWallTexture (-1, -1, "Texture viewer", NumWTexture, WTexture,
+	   buf);
+	 ForgetWTextureNames ();
+      }
+      TermGfx ();
+      viewtex_end:;
+      }
+
+   /* user asked to save an object to a separate pwad file */
+   else if (strcmp (com, "save") == 0 || strcmp (com, "s") == 0)
+      {
+      com = strtok (NULL, " ");
+      if (com == NULL)
+	 {
+	 printf ("Object name argument missing.\n");
+	 continue;
+	 }
+      if (strlen (com) > WAD_NAME || strchr (com, '.') != NULL)
+	 {
+	 printf ("Invalid object name.\n");
+	 continue;
+	 }
+      out = strtok (NULL, " ");
+      if (out == NULL)
+	 {
+	 printf ("Wad file name argument missing.\n");
+	 continue;
+	 }
+      if (wad_already_loaded (com))
+	 {
+	 printf ("%s: in use, close it first\n", com);
+	 continue;
+	 }
+      printf ("Saving directory entry data to \"%s\".\n", out);
+      if ((file = fopen (out, "wb")) == NULL)
+	 fatal_error ("error opening output file \"%s\"", out);
+      SaveDirectoryEntry (file, com);
+      fclose (file);
+      }
+
+   /* user asked to encapsulate a raw file in a pwad file */
+   else if (strcmp (com, "insert") == 0 || strcmp (com, "i") == 0)
+      {
+      com = strtok (NULL, " ");
+      if (com == NULL)
+	 {
+	 printf ("Raw file name argument missing.\n");
+	 continue;
+	 }
+      out = strtok (NULL, " ");
+      if (out == NULL)
+	 {
+	 printf ("Object name argument missing.\n");
+	 continue;
+	 }
+      if (strlen (out) > WAD_NAME || strchr (out, '.') != NULL)
+	 {
+	 printf ("Invalid object name.\n");
+	 continue;
+	 }
+      if ((raw = fopen (com, "rb")) == NULL)
+	 fatal_error ("error opening input file \"%s\"", com);
+      /* kluge */
+      strcpy (input, out);
+      strcat (input, ".wad");
+      if (wad_already_loaded (input))
+	 {
+	 printf ("%s: in use, close it first\n", input);
+	 continue;
+	 }
+      printf ("Including new object %s in \"%s\".\n", out, input);
+      if ((file = fopen (input, "wb")) == NULL)
+	 fatal_error ("error opening output file \"%s\"", input);
+      SaveEntryFromRawFile (file, raw, out);
+      fclose (raw);
+      fclose (file);
+      }
+
+   /* user asked to extract an object to a raw binary file */
+   else if (strcmp (com, "xtract") == 0
+	 || strcmp (com, "extract") == 0
+	 || strcmp (com, "x") == 0)
+      {
+      com = strtok (NULL, " ");
+      if (com == NULL)
+	 {
+	 printf ("Object name argument missing.\n");
+	 continue;
+	 }
+      if (strlen (com) > WAD_NAME || strchr (com, '.') != NULL)
+	 {
+	 printf ("Invalid object name.\n");
+	 continue;
+	 }
+      out = strtok (NULL, " ");
+      if (out == NULL)
+	 {
+	 printf ("Raw file name argument missing.\n");
+	 continue;
+	 }
+      if (wad_already_loaded (com))
+	 {
+	 printf ("%s: in use, close it first\n", com);
+	 printf ("Besides do you really want to overwrite a wad file with"
+		 " raw data ?\n");
+	 continue;
+	 }
+      printf ("Saving directory entry data to \"%s\".\n", out);
+      if ((file = fopen (out, "wb")) == NULL)
+	 fatal_error ("error opening output file \"%s\"", out);
+      SaveEntryToRawFile (file, com);
+      fclose (file);
+      }
+
+   /* unknown command */
+   else
+      printf ("Unknown command \"%s\"!\n", com);
+   }
+}
+
+
+/*
+ *	add_base_colours
+ *	Add the NCOLOURS base colours to the list of
+ *	application colours.
+ */
+static void add_base_colours ()
+{
+for (size_t n = 0; n < NCOLOURS; n++)
+   {
+   rgb_c c;
+
+   // The first 16 are the standard IRGB VGA colours.
+   // FIXME they're to be removed and replaced by
+   // "logical" colours.
+#ifdef WHITE_BACKGROUND
+   if (n == 0)
+      irgb2rgb (15, &c);
+   else if (n == 15)
+      irgb2rgb (0, &c);
+   else
+#endif
+      if (n < 16)
+      irgb2rgb (n, &c);
+
+   // Then there are the colours used to draw the
+   // windows and the map. The colours used to draw
+   // the things are parametrized in the .ygd ; they
+   // are added by load_game().
+   // FIXME they should not be hard-coded, of course !
+
+   /* WINBG* is for window backgrounds. Use the _HL variant is
+      for highlighted parts of windows (E.G. the current line in
+      a menu). _LIGHT and _DARK are for window borders and
+      grooves. There is no _HL flavour of these because I didn't
+      feel the need. */
+#ifdef WHITE_BACKGROUND
+   else if (n == WINBG)			c.set (0xe2, 0xdc, 0xd6);
+   else if (n == WINBG_LIGHT)		c.set (0xee, 0xe8, 0xe2);
+   else if (n == WINBG_DARK)		c.set (0xc3, 0xbe, 0xb9);
+   else if (n == WINBG_HL)		c.set (0xf4, 0xee, 0xe7);
+#else
+   else if (n == WINBG)			c.set (0x2a, 0x24, 0x18);
+   else if (n == WINBG_LIGHT)		c.set (0x48, 0x42, 0x3c);
+   else if (n == WINBG_DARK)		c.set (0x20, 0x1b, 0x12);
+   else if (n == WINBG_HL)		c.set (0x58, 0x50, 0x48);
+#endif
+
+   /* WINFG* is for regular text. _DIM is for greyed out text
+      (for disabled options or text that is not applicable). */
+#ifdef WHITE_BACKGROUND
+   else if (n == WINFG)			c.set (0x60, 0x60, 0x60);
+   else if (n == WINFG_HL)		c.set (0x30, 0x30, 0x30);
+   else if (n == WINFG_DIM)		c.set (0xB8, 0xB8, 0xB8);
+   else if (n == WINFG_DIM_HL)		c.set (0x90, 0x90, 0x90);
+#else
+   else if (n == WINFG)			c.set (0xa0, 0xa0, 0xa0);
+   else if (n == WINFG_HL)		c.set (0xd0, 0xd0, 0xd0);
+   else if (n == WINFG_DIM)		c.set (0x48, 0x48, 0x48);
+   else if (n == WINFG_DIM_HL)		c.set (0x70, 0x70, 0x70);
+#endif
+
+   /* WINLABEL is for text of lesser importance. For example,
+      the brackets around key binding are displayed in WINLABEL,
+      while what's between them is displayed in WINFG. The
+      difference with WINFG is not very noticeable but it does
+      improve readability. The static text in the object info
+      windows should be displayed in WINLABEL. */
+#ifdef WHITE_BACKGROUND
+   else if (n == WINLABEL)		c.set (0x88, 0x88, 0x88);
+   else if (n == WINLABEL_HL)		c.set (0x60, 0x60, 0x60);
+   else if (n == WINLABEL_DIM)		c.set (0xc8, 0xc8, 0xc8);
+   else if (n == WINLABEL_DIM_HL)	c.set (0xb0, 0xb0, 0xb0);
+#else
+   else if (n == WINLABEL)		c.set (0x78, 0x78, 0x78);
+   else if (n == WINLABEL_HL)		c.set (0xa0, 0xa0, 0xa0);
+   else if (n == WINLABEL_DIM)		c.set (0x38, 0x38, 0x38);
+   else if (n == WINLABEL_DIM_HL)	c.set (0x50, 0x50, 0x50);
+#endif
+
+#ifdef WHITE_BACKGROUND
+   else if (n == GRID1)			c.set (0x80, 0x80, 0xff);
+   else if (n == GRID2H)		c.set (0xf0, 0xf0, 0xff);
+   else if (n == GRID2V)		c.set (0xf0, 0xf0, 0xff);
+   else if (n == GRID3H)		c.set (0xd0, 0xd0, 0xff);
+   else if (n == GRID3V)		c.set (0xd0, 0xd0, 0xff);
+   else if (n == GRID4H)		c.set (0xb0, 0xb0, 0xff);
+   else if (n == GRID4V)		c.set (0xb0, 0xb0, 0xff);
+#else
+   else if (n == GRID1)			c.set (0, 0, 0xc0);
+   else if (n == GRID2H)		c.set (0, 0, 0x30);
+   else if (n == GRID2V)		c.set (0, 0, 0x40);
+   else if (n == GRID3H)		c.set (0, 0, 0x50);
+   else if (n == GRID3V)		c.set (0, 0, 0x70);
+   else if (n == GRID4H)		c.set (0, 0, 0x80);
+   else if (n == GRID4V)		c.set (0, 0, 0xc0);
+#endif
+
+   else if (n == LINEDEF_NO)		c.set (0x40, 0xd0, 0xf0);
+   else if (n == SECTOR_NO)		c.set (0x40, 0xd0, 0xf0);
+   else if (n == THING_NO)		c.set (0x40, 0xd0, 0xf0);
+   else if (n == VERTEX_NO)		c.set (0x40, 0xd0, 0xf0);
+   else if (n == CLR_ERROR)		c.set (0xff, 0,    0);
+   else if (n == THING_REM)		c.set (0x40, 0x40, 0x40);
+
+   else if (n == SECTOR_TAG)		c.set (0x00, 0xff, 0x00);
+   else if (n == SECTOR_TAGTYPE)	c.set (0x00, 0xe0, 0xe0);
+   else if (n == SECTOR_TYPE)		c.set (0x00, 0x80, 0xff);
+
+#ifdef WHITE_BACKGROUND
+   else if (n == WINTITLE)		c.set (0xb0, 0x80, 0x00);
+#else
+   else if (n == WINTITLE)		c.set (0xff, 0xff, 0x00);
+#endif
+
+   else					fatal_error ("Wrong acn %d", n);
+
+   acolour_t acn = add_app_colour (c);
+   if (acn != n)
+      fatal_error ("add_base_colours: got %d for %d\n", acn, n);
+   }
+}
+
+
+static const Wad_file *wad_by_name (const char *pathname)
+{
+  const Wad_file *wf;
+
+  for (wad_list.rewind (); wad_list.get (wf);)
+    if (fncmp (pathname, wf->pathname ()) == 0)
+      return wf;
+  return 0;
+}
+
+
+static bool wad_already_loaded (const char *pathname)
+{
+  return wad_by_name (pathname) != 0;
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/yadex.h	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,599 @@
+/*
+ *	yadex.h
+ *	The header that all modules include.
+ *	BW & RQ sometime in 1993 or 1994.
+ */
+
+
+/*
+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.
+*/
+
+
+#ifndef YH_YADEX  /* DO NOT INSERT ANYTHING BEFORE THIS LINE */
+#define YH_YADEX
+
+
+#include "config.h"
+
+
+// Sanity checks
+#if ! (defined Y_BGI ^ defined Y_X11)
+#error "You must #define either Y_BGI or Y_X11"
+#endif
+
+#if ! (defined Y_DOS ^ defined Y_UNIX)
+#error "You must #define either Y_DOS or Y_UNIX"
+#endif
+
+
+/*
+ *	Standard headers
+ */
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <ctype.h>
+#include <limits.h>
+#include <errno.h>
+#ifdef Y_DOS
+#include <alloc.h>
+#include <dos.h>
+#include <bios.h>
+#elif defined Y_UNIX
+#include <unistd.h>
+#define far
+#define huge
+#define farmalloc  malloc
+#define farrealloc realloc
+#define farfree    free
+#endif
+
+
+/*
+ *	Additional libraries
+ */
+#ifdef Y_BGI 
+#include <graphics.h>
+#endif
+#include <atclib.h>
+#include "bitvec.h"  /* bv_set, bv_clear, bv_toggle */
+#include "yerror.h"
+#include "aym.h"     /* Needs yerror.h */
+#include "windim.h"
+#include "ymemory.h"
+
+
+/*
+ *	Platform-independant types and formats.
+ */
+typedef unsigned char  u8;
+typedef signed   char  i8;
+
+typedef unsigned short u16;
+#define F_U16_D "hu"
+#define F_U16_H "hX"
+
+typedef signed   short i16;
+#define F_I16_D "hd"
+#define F_I16_H "hX"
+
+typedef unsigned long  u32;
+#define F_U32_D "lu"
+#define F_U32_H "lX"
+
+typedef signed   long  i32;
+#define F_I32_D "ld"
+#define F_I32_H "lX"
+
+
+/*
+ *	Platform definitions
+ */
+#if defined Y_DOS
+const int Y_PATH      = 64;	// Maximum length of a path
+const int Y_FILE_NAME = 255;	// Maximum length of file name, including path
+#elif defined Y_UNIX
+const int Y_PATH      = 255;
+const int Y_FILE_NAME = 255;
+#endif
+typedef char y_file_name_t[Y_FILE_NAME + 1];
+
+
+/*
+ *	Constants of the universe.
+ */
+const double HALFPI = 1.5707963;
+const double ONEPI  = 3.1415926;
+const double TWOPI  = 6.2831852;
+const double ANSWER = 42;
+
+
+/*
+ *	Syntactic sugar
+ */
+#define y_min(a,b) ((a) < (b) ? (a) : (b))
+#define y_max(a,b) ((a) > (b) ? (a) : (b))
+const char *const Y_NULL = 0;  // NULL (const char *)
+
+
+/*
+ *	To avoid including certain headers.
+ */
+class rgb_c;
+
+
+#include "wstructs.h"
+
+
+/*
+ *	Doom definitions
+ *	Things about the Doom engine
+ *	FIXME should move as much of this as possible to the ygd file...
+ *	FIXME Hexen has a different value for MIN_DEATHMATH_STARTS
+ */
+const int DOOM_PLAYER_HEIGHT         = 56;
+const int DOOM_FLAT_WIDTH            = 64;
+const int DOOM_FLAT_HEIGHT           = 64;
+const size_t DOOM_MIN_DEATHMATCH_STARTS = 4;
+const size_t DOOM_MAX_DEATHMATCH_STARTS = 10;
+const size_t DOOM_COLOURS               = 256;
+typedef enum { YGPF_NORMAL, YGPF_ALPHA, YGPF_PR } ygpf_t;
+typedef enum { YGTF_NORMAL, YGTF_NAMELESS, YGTF_STRIFE11 } ygtf_t;
+typedef enum { YGTL_NORMAL, YGTL_TEXTURES, YGTL_NONE } ygtl_t;
+
+
+/*
+ *	Directory
+ */
+/* The wad file pointer structure is used for holding the information
+   on the wad files in a linked list.
+   The first wad file is the main wad file. The rest are patches. */
+class Wad_file;
+
+/* The master directory structure is used to build a complete directory
+   of all the data blocks from all the various wad files. */
+typedef struct MasterDirectory huge *MDirPtr;
+struct MasterDirectory
+   {
+   MDirPtr next;		// Next in list
+   const Wad_file *wadfile;	// File of origin
+   struct Directory dir;	// Directory data
+   };
+
+/* Lump location : enough information to load a lump without
+   having to do a directory lookup. */
+struct Lump_loc
+   {
+   Lump_loc () { wad = 0; }
+   Lump_loc (const Wad_file *w, i32 o, i32 l) { wad = w; ofs = o; len = l; }
+   bool operator == (const Lump_loc& other) const
+     { return wad == other.wad && ofs == other.ofs && len == other.len; }
+   const Wad_file *wad;
+   i32 ofs;
+   i32 len;
+   };
+#include "wstructs.h"
+
+
+/*
+ *	The colour system.
+ *	FIXME: only the logical side of the colour system
+ *	should be declared here. The physical side should
+ *	be moved to a less used header as very few modules
+ *	need to know about it.
+ */
+/* acolour_t -- an application colour number.
+   Several different application colours may refer to the same
+   physical colour. */
+typedef u8 acolour_t;
+#define ACOLOUR_NONE 0xff  // The out-of-band value
+
+#ifndef Y_BGI
+/* The 16 VGA colours that DEU used to use.
+   For the BGI version, those macros are defined in graphics.h
+   FIXME: all references to these in the code should be removed. */
+const acolour_t BLACK           = 0;
+const acolour_t BLUE            = 1;
+const acolour_t GREEN           = 2;
+const acolour_t CYAN            = 3;
+const acolour_t RED             = 4;
+const acolour_t MAGENTA         = 5;
+const acolour_t BROWN           = 6;
+const acolour_t LIGHTGREY       = 7;
+const acolour_t DARKGREY        = 8;
+const acolour_t LIGHTBLUE       = 9;
+const acolour_t LIGHTGREEN      = 10;
+const acolour_t LIGHTCYAN       = 11;
+const acolour_t LIGHTRED        = 12;
+const acolour_t LIGHTMAGENTA    = 13;
+const acolour_t YELLOW          = 14;
+const acolour_t WHITE           = 15;
+#endif
+
+// True logical colours
+const acolour_t WINBG           = 16;
+const acolour_t WINBG_LIGHT     = 17;
+const acolour_t WINBG_DARK      = 18;
+const acolour_t WINBG_HL        = 19;
+
+const acolour_t WINFG           = 20;
+const acolour_t WINFG_HL        = 21;
+const acolour_t WINFG_DIM       = 22;
+const acolour_t WINFG_DIM_HL    = 23;
+
+const acolour_t WINLABEL        = 24;
+const acolour_t WINLABEL_HL     = 25;
+const acolour_t WINLABEL_DIM    = 26;
+const acolour_t WINLABEL_DIM_HL = 27;
+
+const acolour_t GRID1           = 28;
+const acolour_t GRID2H          = 29;
+const acolour_t GRID2V          = 30;
+const acolour_t GRID3H          = 31;
+const acolour_t GRID3V          = 32;
+const acolour_t GRID4H          = 33;
+const acolour_t GRID4V          = 34;
+const acolour_t LINEDEF_NO      = 35;
+const acolour_t SECTOR_NO       = 36;
+const acolour_t THING_NO        = 37;
+const acolour_t VERTEX_NO       = 38;
+const acolour_t CLR_ERROR       = 39;
+const acolour_t THING_REM       = 40;	// Things when not in things mode
+
+const acolour_t SECTOR_TAG      = 41;
+const acolour_t SECTOR_TAGTYPE  = 42;
+const acolour_t SECTOR_TYPE     = 43;
+
+const acolour_t WINTITLE        = 44;
+
+const acolour_t NCOLOURS        = 45;
+
+
+/*
+ *	More stuff
+ */
+// The actual definition is in selectn.h
+typedef struct SelectionList *SelPtr;
+// Operations on the selection :
+typedef enum
+{
+  YS_ADD    = BV_SET,	// Add to selection
+  YS_REMOVE = BV_CLEAR,	// Remove from selection
+  YS_TOGGLE = BV_TOGGLE	// If not in selection, add; else, remove
+} sel_op_t;
+
+// Confirmation options are stored internally this way :
+typedef enum
+   {
+   YC_YES      = 'y',
+   YC_NO       = 'n',
+   YC_ASK      = 'a',
+   YC_ASK_ONCE = 'o'
+   } confirm_t;
+
+// Bit bashing operations
+const int YO_AND    = 'a';  // Argument = mask
+const int YO_CLEAR  = 'c';  // Argument = bit#
+const int YO_COPY   = 'd';  // Argument = source_bit# dest_bit#
+const int YO_OR     = 'o';  // Argument = mask
+const int YO_SET    = 's';  // Argument = bit#
+const int YO_TOGGLE = 't';  // Argument = bit#
+const int YO_XOR    = 'x';  // Argument = mask
+
+
+/*
+ *	Even more stuff ("the macros and constants")
+ */
+
+extern const char *const log_file;        // "yadex.log"
+extern const char *const msg_unexpected;  // "unexpected error"
+extern const char *const msg_nomem;       // "Not enough memory"
+
+// Convert screen/window coordinates to map coordinates
+#define MAPX(x)		(OrigX + (int) (((int) (x) - ScrCenterX) / Scale))
+#define MAPY(y)		(OrigY + (int) ((ScrCenterY - (int) (y)) / Scale))
+
+// Convert map coordinates to screen/window coordinates
+#define SCREENX(x)	(ScrCenterX + (int) (((x) - OrigX) * Scale))
+#define SCREENY(y)	(ScrCenterY + (int) ((OrigY - (y)) * Scale))
+
+// AYM 19980213: InputIntegerValue() uses this to mean that Esc was pressed
+#define IIV_CANCEL  INT_MIN
+
+
+/*
+ *	Not real variables -- just a way for functions
+ *	that return pointers to report errors in a better
+ *	fashion than by just returning NULL and setting
+ *	a global variable.
+ */
+extern char error_non_unique[1];  // Found more than one
+extern char error_none[1];        // Found none
+extern char error_invalid[1];     // Invalid parameter
+
+
+/*
+ *	Interfile global variables
+ */
+
+// Defined in yadex.cc
+extern const char *install_dir; 	// Where yadex is installed
+extern FILE *logfile;			// Filepointer to the error log
+extern bool  Registered;		// Registered or shareware iwad ?
+extern int screen_lines;		// Lines that our TTY can display
+extern int remind_to_build_nodes;	// Remind the user to build nodes
+
+// Defined in yadex.c and set from
+// command line and/or config file
+extern bool  autoscroll;	// Autoscrolling enabled.
+extern unsigned long autoscroll_amp;// Amplitude in percents of screen/window size.
+extern unsigned long autoscroll_edge; // Max. dist. in pixels to edge.
+extern const char *config_file;	// Name of the configuration file
+extern int   copy_linedef_reuse_sidedefs;
+extern int   cpu_big_endian;	// Am I running on a big-endian CPU ?
+extern bool  Debug;			// Are we debugging?
+extern int   default_ceiling_height;			// For new sectors
+extern char  default_ceiling_texture[WAD_FLAT_NAME + 1];// For new sectors
+extern int   default_floor_height;			// For new sectors
+extern char  default_floor_texture[WAD_FLAT_NAME + 1];	// For new sectors
+extern int   default_light_level;			// For new sectors
+extern char  default_lower_texture[WAD_TEX_NAME + 1];	// For new linedefs
+extern char  default_middle_texture[WAD_TEX_NAME + 1];	// For new linedefs
+extern int   default_thing;				// For new THINGS
+extern char  default_upper_texture[WAD_TEX_NAME + 1];	// For new linedefs
+extern int   double_click_timeout;// Max ms between clicks of double click.
+extern bool  Expert;		// Don't ask for confirmation for some ops.
+extern const char *Game;	// Name of game "doom", "doom2", "heretic", ...
+extern int   grid_pixels_min;   // Minimum grid step in pixels when not locked
+extern int   GridMin;	 	// Minimum grid step in map units
+extern int   GridMax;		// Maximum grid step in map units
+extern int   idle_sleep_ms;	// Time to sleep after empty XPending()
+extern int   zoom_default;	// Initial zoom factor for map
+extern int   zoom_step;		// Step between zoom factors in percent
+extern int   digit_zoom_base;	// Zoom factor of `1' key, in percent
+extern int   digit_zoom_step;	// Step between digit keys, in percent 
+extern confirm_t insert_vertex_merge_vertices;
+extern confirm_t insert_vertex_split_linedef;
+extern bool  blindly_swap_sidedefs;
+extern const char *Iwad1;	// Name of the Doom iwad
+extern const char *Iwad2;	// Name of the Doom II iwad
+extern const char *Iwad3;	// Name of the Heretic iwad
+extern const char *Iwad4;	// Name of the Hexen iwad
+extern const char *Iwad5;	// Name of the Strife iwad
+extern const char *Iwad6;	// Name of the Doom alpha 0.2 iwad
+extern const char *Iwad7;	// Name of the Doom alpha 0.4 iwad
+extern const char *Iwad8;	// Name of the Doom alpha 0.5 iwad
+extern const char *Iwad9;	// Name of the Doom press release iwad
+extern const char *Iwad10;	// Name of the Strife 1.0 iwad
+extern const char *MainWad;	// Name of the main wad file
+#ifdef AYM_MOUSE_HACKS
+extern int   MouseMickeysH; 
+extern int   MouseMickeysV; 
+#endif
+extern char **PatchWads;	// List of pwad files
+extern bool  Quiet;		// Don't beep when an object is selected
+extern bool  Quieter;		// Don't beep, even on error
+extern unsigned long scroll_less;// %s of screenful to scroll by
+extern unsigned long scroll_more;// %s of screenful to scroll by
+extern bool  Select0;		// Autom. select obj. 0 when switching modes
+extern int   show_help;		// Print usage message and exit.
+extern int   sprite_scale;	// Relative scale used to display sprites
+extern bool  SwapButtons;	// Swap right and middle mouse buttons
+extern int   verbose;		// Verbose mode
+extern int   welcome_message;	// Print the welcome message on startup.
+extern const char *bench;	// Benchmark to run
+
+// Defined in gfx.cc
+extern int   ScrMaxX;		// Maximum display X-coord of screen/window
+extern int   ScrMaxY;		// Maximum display Y-coord of screen/window
+extern float Scale;		// Scale to draw map 20 to 1
+
+// Defined in wads.cc
+extern MDirPtr   MasterDir;	// The master directory
+class Serial_num;
+extern Serial_num master_dir_serial;	// The revision# thereof
+
+// Defined in edit.cc
+extern bool InfoShown;          // Is the bottom line displayed?
+
+// Defined in mouse.cc
+#if defined Y_BGI
+extern bool UseMouse;		// Is there a mouse driver?
+#elif defined Y_X11
+#define UseMouse 1
+#endif
+
+
+/*
+ *	Prototypes
+ *	AYM 1998-10-16: DEU used to have _all_ prototypes here. Thus
+ *	I had to recompile _all_ the modules every time I changed
+ *	a single prototype. To avoid this, my theory is to put all
+ *	the prototypes I can in individual headers. There is still
+ *	room for improvement on that matter...
+ */
+
+// checks.cc (previously in editobj.cc)
+void CheckLevel (int, int, int pulldown); /* SWAP! */
+bool CheckStartingPos (void); /* SWAP! */
+
+// colour1.cc
+int getcolour (const char *s, rgb_c *rgb);
+
+// colour2.cc
+int rgb2irgb (int r, int g, int b);
+
+// colour3.cc
+void irgb2rgb (int c, rgb_c *rgb);
+
+// editobj.cc
+int InputObjectNumber (int, int, int, int);
+int InputObjectXRef (int, int, int, bool, int);
+bool Input2VertexNumbers (int, int, const char *, int *, int *);
+void EditObjectsInfo (int, int, int, SelPtr);
+void InsertStandardObject (int, int, int choice); /* SWAP! */
+void MiscOperations (int, SelPtr *, int choice); /* SWAP! */
+
+// game.cc
+void InitGameDefs (void);
+void LoadGameDefs (const char *game);
+void FreeGameDefs (void);
+
+// geom.cc
+unsigned ComputeAngle (int, int);
+unsigned ComputeDist (int, int);
+
+// input.cc
+#include "input.h"
+
+// l_align.cc (previously in objects.cc)
+void AlignTexturesY (SelPtr *); /* SWAP! */
+void AlignTexturesX (SelPtr *); /* SWAP! */
+
+// l_misc.cc (previously in objects.cc)
+void FlipLineDefs (SelPtr, bool); /* SWAP! */
+void SplitLineDefs (SelPtr); /* SWAP! */
+void MakeRectangularNook (SelPtr obj, int width, int depth, int convex); /* SWAP! */
+void SetLinedefLength (SelPtr obj, int length, int move_2nd_vertex);
+
+// l_prop.cc (previously in editobj.cc)
+void LinedefProperties (int x0, int y0, SelPtr obj);
+
+// l_unlink.cc
+void unlink_sidedef (SelPtr linedefs, int side1, int side2);
+
+// levels.cc
+int ReadLevelData (const char *); /* SWAP! */
+void ForgetLevelData (void); /* SWAP! */
+int SaveLevelData (const char *, const char *level_name); /* SWAP! */
+void ReadWTextureNames (void);
+void ForgetFTextureNames (void);
+int is_flat_name_in_list (const char *name);
+void ReadFTextureNames (void);
+void ForgetWTextureNames (void);
+
+// mouse.cc (this module is entirely DOS-specific)
+#if defined Y_BGI
+void CheckMouseDriver (void);
+void ShowMousePointer (void);
+void HideMousePointer (void);
+void GetMouseCoords (int *, int *, int *);
+void SetMouseCoords (int, int);
+void SetMouseLimits (int, int, int, int);
+void ResetMouseLimits (void);
+void MouseCallBackFunction (void);
+#elif defined Y_X11
+#define CheckMouseDriver nop
+#define ShowMousePointer nop
+#define HideMousePointer nop
+#define GetMouseCoords   nop
+#define SetMouseCoords   nop
+#define SetMouseLimits   nop
+#define ResetMouseLimits nop
+#endif
+
+// names.cc
+const char *GetObjectTypeName (int);
+const char *GetEditModeName (int);
+const char *GetLineDefTypeName (int);
+const char *GetLineDefTypeLongName (int);
+const char *GetLineDefFlagsName (int);
+const char *GetLineDefFlagsLongName (int);
+const char *GetSectorTypeName (int);
+const char *GetSectorTypeLongName (int);
+
+// nop.cc
+void nop (...);
+
+// s_door.cc (previously in objects.cc)
+void MakeDoorFromSector (int); /* SWAP! */
+
+// s_lift.cc (previously in objects.cc)
+void MakeLiftFromSector (int); /* SWAP! */
+
+// s_merge.cc (previously in objects.cc)
+void MergeSectors (SelPtr *); /* SWAP! */
+void DeleteLineDefsJoinSectors (SelPtr *); /* SWAP! */
+
+// s_misc.cc (previously in objects.cc)
+void DistributeSectorFloors (SelPtr); /* SWAP! */
+void DistributeSectorCeilings (SelPtr); /* SWAP! */
+void RaiseOrLowerSectors (SelPtr obj);
+void BrightenOrDarkenSectors (SelPtr obj);
+
+// s_prop.cc (previously in editobj.cc)
+void SectorProperties (int x0, int y0, SelPtr obj);
+
+// s_split.cc (previously in objects.cc)
+void SplitSector (int, int); /* SWAP! */
+void SplitLineDefsAndSector (int, int); /* SWAP! */
+
+// swapmem.cc
+void InitSwap (void);
+void FreeSomeMemory (void);
+void ObjectsNeeded (int, ...);
+
+// scrnshot.cc
+void ScreenShot (void);
+
+// selrect.cc
+// t_prop.c (previously in editobj.c)
+void ThingProperties (int x0, int y0, SelPtr obj);
+
+// v_merge.cc
+void DeleteVerticesJoinLineDefs (SelPtr ); /* SWAP! */
+void MergeVertices (SelPtr *); /* SWAP! */
+bool AutoMergeVertices (SelPtr *, int obj_type, char operation); /* SWAP! */
+
+// v_polyg.cc
+void InsertPolygonVertices (int, int, int, int);
+
+// verbmsg.cc
+void verbmsg (const char *fmt, ...);
+
+// version.cc
+extern const char *const yadex_version;
+extern const char *const yadex_source_date;
+
+// prefix.cc
+extern const char *const yadex_etc_version;
+extern const char *const yadex_etc_common;
+extern const char *const yadex_ygd_version;
+extern const char *const yadex_ygd_common;
+
+// wads.cc
+MDirPtr FindMasterDir (MDirPtr, const char *);
+MDirPtr FindMasterDir (MDirPtr, const char *, const char *);
+int entryname_cmp (const char *entry1, const char *entry2);
+
+// warning.cc
+void warn (const char *fmt, ...);
+
+// yadex.cc
+void Beep (void);
+void PlaySound (int, int);
+void LogMessage (const char *, ...);
+
+
+#endif  /* DO NOT ADD ANYTHING AFTER THIS LINE */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/yerror.h	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,12 @@
+/*
+ *	yerror.h
+ *	AYM 1999-03-24
+ */
+
+
+void fatal_error (const char *fmt, ...);
+void err (const char *fmt, ...);
+void nf_bug (const char *fmt, ...);
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/ymemory.h	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,15 @@
+/*
+ *	ymemory.h
+ *	Memory allocation functions.
+ *	AYM 1999-03-24
+ */
+
+
+void *GetMemory (unsigned long size);
+void *ResizeMemory (void *, unsigned long size);
+void FreeMemory (void *);
+void huge *GetFarMemory (unsigned long size);
+void huge *ResizeFarMemory (void huge *old, unsigned long size);
+void FreeFarMemory (void huge *);
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/ytime.cc	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,59 @@
+/*
+ *	ytime.cc
+ *	AYM 1999-11-11
+ */
+
+
+/*
+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 <time.h>
+#include <sys/time.h>
+#include <unistd.h>
+
+#include "ytime.h"
+
+
+/*
+ *	Return the current time in ms
+ */
+unsigned long y_milliseconds ()
+{
+#ifdef Y_GETTIMEOFDAY
+  struct timeval tv;
+  struct timezone tz;
+  if (gettimeofday (&tv, &tz))
+  {
+    nf_bug ("gettimeofday() error (%s)", strerror (errno));
+    return 0;
+  }
+  return tv.tv_sec * 1000 + tv.tv_usec / 1000;
+#else  /* Sucks ! */
+  static const double ms_per_clock = 1000.0 / CLOCKS_PER_SEC;
+  return (unsigned long) (clock () * ms_per_clock);
+#endif
+}
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/ytime.h	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,14 @@
+/*
+ *	ytime.h
+ *	AYM 1999-11-11
+ */
+
+
+#ifndef YH_YTIME  /* DO NOT INSERT ANYTHING BEFORE THIS LINE */
+#define YH_YTIME
+
+
+unsigned long y_milliseconds ();
+
+
+#endif  /* DO NOT ADD ANYTHING AFTER THIS LINE */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/yadex.cfg	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,285 @@
+# Yadex configuration file version 4
+# ^ Don't modify the line above, it's there for something.
+
+
+#
+#	Resources
+#
+
+# The names of the iwads.
+# #  -g       Description
+# -- -------- -------------------------------------------------
+#  1 doom     Doom (shareware or registered) and Ultimate Doom.
+#  2 doom2    Doom II and Final Doom
+#  3 heretic  Heretic (shareware or registered)
+#  4 hexen    Hexen (demo or commerical)
+#  5 strife   Strife 1.1 and later (demo or commercial)
+#  6 doom02   Doom alpha 0.2 (ftp.cdrom.com /pub/idgames/historic/doom0_2.zip)
+#  7 doom04   Doom alpha 0.4 (ftp.cdrom.com /pub/idgames/historic/doom0_4.zip)
+#  8 doom05   Doom alpha 0.5 (ftp.cdrom.com /pub/idgames/historic/doom0_5.zip)
+#  9 doompr   Doom press release pre-beta (/pub/idgames/historic/doomprbt.zip)
+# 10 strife10 Strife 1.0 (demo or commercial)
+
+  iwad1  = /usr/local/share/games/doom/doom.wad
+  iwad2  = /usr/local/share/games/doom2/doom2.wad
+  iwad3  = /usr/local/share/games/heretic/heretic.wad
+  iwad4  = /usr/local/share/games/hexen/hexen.wad
+  iwad5  = /usr/local/share/games/strife/strife1.wad
+  iwad6  = /usr/local/share/games/doom02/doom.wad
+  iwad7  = /usr/local/share/games/doom04/doom.wad
+  iwad8  = /usr/local/share/games/doom05/doom.wad
+  iwad9  = /usr/local/share/games/doompr/doompres.wad
+  iwad10 = /usr/local/share/games/strife10/strife1.wad
+
+# Name of the patch wads you want to load. None by default.
+
+  #file = raphael.wad
+  #file = brendon.wad
+
+
+#
+#	Editing options
+#
+
+# Name of the default game ("doom", "doom02", "doom04",
+# "doom05", "doom2", "doompr", "heretic", "hexen" or "strife").
+# Can be overridden by -g or YADEX_GAME. This parameter has no
+# default value.
+
+  game = doom2
+
+# If you set it to yes, when you copy a group of linedefs, each
+# new linedef will use the same sidedefs as its model.  This
+# makes for leaner wad files but you better know what you're
+# doing ! Off by default.
+
+  #copy_linedef_reuse_sidedefs = no
+
+# [Deprecated] Answers "Yes" to many confirmation prompts. Off
+# by default. This option will be replaced by individual
+# confirmation options.
+
+  #expert = false
+
+# Finer-grained confirmation options.
+# Those variables can be set to one of three values :
+#   "yes"      : don't prompt you, act as if you answered "yes",
+#   "no"       : don't prompt you, act as if you answered "no",
+#   "ask"      : always prompt you,
+#   "ask_once" : prompt you only for the first item of a group.
+
+# If you insert a new vertex on top of an existing vertex,
+# should we merge the two vertices ? Default is "ask_once".
+
+  #insert_vertex_merge_vertices = yes
+
+# If you insert a new vertex on top of an existing linedef,
+# should we split the linedef there ? Default is "ask_once".
+
+  #insert_vertex_split_linedef = yes
+
+# Blindly swap the sidedefs on a linedef, i.e. without any
+# warning prompt. Default is false.
+
+  #blindly_swap_sidedefs = false
+
+# Is the infobar shown ? On by default.
+
+  #info_bar = true
+
+# Set this to true if you want to have the object 0
+# automatically selected when you switch from one editing mode
+# to another. Off by default.
+
+  #select0 = false
+
+# Bounds of grid step.
+
+  #grid_max        = 128
+  #grid_min        = 2
+  #grid_pixels_min = 10
+
+# Default attributes of new things, linedefs, sidedefs and
+# sectors. 3004 is the number for a former human.
+
+  #default_ceiling_height  = 128
+  #default_ceiling_texture = CEIL3_5
+  #default_floor_height    = 0
+  #default_floor_texture   = FLOOR4_8
+  #default_light_level     = 144
+  #default_lower_texture   = STARTAN3
+  #default_middle_texture  = STARTAN3
+  #default_thing           = 3004
+  #default_upper_texture   = STARTAN3
+
+# Initial zoom factor when opening a new edit window, in
+# percent. The special value 0 causes Yadex to adjust the zoom
+# factor so that the level fills the window, as if you had
+# pressed [`]. It's the default.
+
+  #zoom_default = 0
+
+# Ratio between two sucessive zoom factors, in percent. The
+# scale is increased by that many percent every time you zoom
+# in. The special value O sets the ratio to the square root of
+# two (slightly above 41% increase). It's the default.
+
+  #zoom_step = 0
+
+# Value to which [1] sets the zoom factor, in percent.
+
+  #digit_zoom_base = 100
+
+# Ratio between successive zoom factors for digit keys, in
+# percent.
+#
+#   [1] sets the zoom factor to digit_zoom_base
+#   [2] sets the zoom factor to digit_zoom_base * digit_zoom_step
+#   [3] sets the zoom factor to digit_zoom_step * digit_zoom_step ** 2
+#   ...
+#   [0] sets the zoom factor to digit_zoom_step * digit_zoom_step ** 9
+#
+# In other words, if this parameter is positive (negative), the
+# zoom factor increases (decreases) across the keyboard. The
+# special value 0 sets the ratio to the inverse of the square
+# root of two, which is about the same thing as setting it to
+# -29. It's the default.
+
+  #digit_zoom_step = 0
+ 
+
+#
+#	Graphic output options
+#
+
+# (X) Use this to set the initial size of the window. If the
+# value is a number, it is taken as a number of pixels. If the
+# value is a percentage, it is taken as a percentage of the
+# corresponding dimension of the screen. Both values default to
+# 90%.
+
+  #width  = 90%
+  #height = 90%
+
+# (DOS) Use this to change the default video mode if you have a
+# SuperVGA driver. (0 = standard VGA, 1 or 2 = 640x480x256, 3 =
+# 800x600x256, 4 = 1024x768x256) Default BGI driver in "vesa".
+# Default mode is 2.
+
+  #bgi   = vesa
+  #video = 2
+
+# (DOS only) Set this if you have an old mouse driver
+# and you don't see the cursor. Off by default.
+
+  #fake_cursor = false
+
+# (X) Set this if you want to use another font than your X
+# server's default one. It's better to choose a fixed-width
+# font. Here are examples of fonts that should be available on
+# all X servers. If Yadex cannot find the specified font, it
+# fall backs on the X server's default font.
+
+  #font = fixed
+  #font = 5x7
+  #font = 5x8
+  #font = 6x9
+  #font = 6x10
+  #font = 6x12
+  #font = 6x13
+  #font = 6x13bold
+  #font = 7x13
+  #font = 7x13bold
+  #font = 7x14
+  #font = 7x14bold
+  #font = 8x13
+  #font = 8x13bold
+  #font = 8x16
+  #font = 9x15
+  #font = 9x15bold
+  #font = 10x20
+  #font = 12x24
+  #font = lucidasanstypewriter-12
+  font = -b&h-lucidatypewriter-medium-r-normal-sans-12-120-75-75-m-70-iso8859-1
+  #font = lucidasanstypewriter-14
+  #font = -schumacher-clean-medium-r-normal--13-130-75-75-c-80-iso8859-1
+  #font = -schumacher-clean-medium-r-normal--14-140-75-75-c-80-iso8859-1
+  #font = -schumacher-clean-medium-r-normal--15-150-75-75-c-90-iso8859-1
+  #font = -schumacher-clean-medium-r-normal--16-160-75-75-c-80-iso8859-1
+
+# The relative scale at which sprites are displayed on the
+# level, in percent. Does *not* affect the sprite viewer or
+# object info box. Default is 100.
+
+  #sprite_scale = 100
+
+
+#
+#	Miscellaneous options
+#
+
+# Autoscrolling is the map scrolling automatically when the
+# pointer comes close to the edge of the window/screen.
+#
+#   autoscroll_amp   The amplitude of the scrolling in percent
+#                    of the screen/window width/height. Default
+#                    is 10.
+#
+#   autoscroll_edge  How near in pixels the pointer must come
+#                    close to the edge of the screen/window for
+#                    autoscrolling to occur. Default is 30.
+#
+#   autoscroll       Controls whether autoscrolling occurs at
+#                    all. Off by default.
+
+  #autoscroll      = false
+  #autoscroll_amp  = 10
+  #autoscroll_edge = 30
+
+# Time in ms to sleep before polling events again if got no
+# event. The shorter the delay, the smoother the response, the
+# more CPU you hog and, if running X over a network, the more
+# bandwidth you use. Above 100 ms, the response starts to be
+# uncomfortably jerky. The default, 50 ms, is fine.
+
+  #idle_sleep_ms = 50
+
+# Users don't need to set this.
+
+  #debug = false
+
+# How close in milliseconds two clicks must be for Yadex to
+# think it's a double click. The default is 200 ms.
+ 
+  #double_click_timeout = 200
+
+# By default, Yadex beeps when you try an invalid command or
+# when it finds an error during the checks. Setting quieter to
+# true prevents it from beeping at all. Setting quiet to true
+# has no effect.
+
+  #quiet   = false
+  #quieter = false
+
+# Amplitude of scrolling in percents of the screen/window
+# width/height. As of this release, the bindings are :
+# - scroll_less:  arrow keys. Default is 10%
+# - scroll_more:  [Pgup], [Pgdn], [Home], [End]. Default is 90%
+
+  #scroll_less = 10
+  #scroll_more = 90
+
+# Make Yadex think that the left and right buttons of the mouse
+# have been swapped. Off by default.
+
+  #swap_buttons = false
+
+# General verbosity level. Can be useful to track down
+# problems. Same thing as "-v". Off by default.
+
+  #verbose = false
+
+# Be helpful to new users. On by default.
+
+  #welcome_message = true
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/yadex.dep	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,1030 @@
+obj/0/acolours.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+dobj/0/acolours.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+obj/0/acolours.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+dobj/0/acolours.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+obj/0/acolours.o: src/wstructs.h src/input.h src/acolours.h src/colour.h
+dobj/0/acolours.o: src/wstructs.h src/input.h src/acolours.h src/colour.h
+obj/0/acolours.o: src/gfx.h src/rgb.h
+dobj/0/acolours.o: src/gfx.h src/rgb.h
+obj/0/aym.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h src/yerror.h
+dobj/0/aym.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h src/yerror.h
+obj/0/aym.o: src/ymemory.h src/aym.h src/windim.h src/wstructs.h src/input.h
+dobj/0/aym.o: src/ymemory.h src/aym.h src/windim.h src/wstructs.h src/input.h
+obj/0/aym.o: src/game.h src/rgb.h
+dobj/0/aym.o: src/game.h src/rgb.h
+obj/0/bench.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+dobj/0/bench.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+obj/0/bench.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h src/wstructs.h
+dobj/0/bench.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h src/wstructs.h
+obj/0/bench.o: src/input.h src/gfx.h src/img.h src/pic2img.h src/wadres.h
+dobj/0/bench.o: src/input.h src/gfx.h src/img.h src/pic2img.h src/wadres.h
+obj/0/bench.o: src/spritdir.h src/lumpdir.h
+dobj/0/bench.o: src/spritdir.h src/lumpdir.h
+obj/0/bitvec.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+dobj/0/bitvec.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+obj/0/bitvec.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+dobj/0/bitvec.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+obj/0/bitvec.o: src/wstructs.h src/input.h
+dobj/0/bitvec.o: src/wstructs.h src/input.h
+obj/0/cfgfile.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+dobj/0/cfgfile.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+obj/0/cfgfile.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+dobj/0/cfgfile.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+obj/0/cfgfile.o: src/wstructs.h src/input.h src/cfgfile.h src/gfx.h src/help1.h
+dobj/0/cfgfile.o: src/wstructs.h src/input.h src/cfgfile.h src/gfx.h src/help1.h
+obj/0/cfgfile.o: src/levels.h src/things.h src/locate.h src/trace.h
+dobj/0/cfgfile.o: src/levels.h src/things.h src/locate.h src/trace.h
+obj/0/checks.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+dobj/0/checks.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+obj/0/checks.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+dobj/0/checks.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+obj/0/checks.o: src/wstructs.h src/input.h src/checks.h src/dialog.h
+dobj/0/checks.o: src/wstructs.h src/input.h src/checks.h src/dialog.h
+obj/0/checks.o: src/gamesky.h src/wadname.h src/gfx.h src/gotoobj.h
+dobj/0/checks.o: src/gamesky.h src/wadname.h src/gfx.h src/gotoobj.h
+obj/0/checks.o: src/levels.h src/things.h src/objects.h src/objid.h
+dobj/0/checks.o: src/levels.h src/things.h src/objects.h src/objid.h
+obj/0/checks.o: src/oldmenus.h src/selectn.h
+dobj/0/checks.o: src/oldmenus.h src/selectn.h
+obj/0/colour1.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+dobj/0/colour1.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+obj/0/colour1.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+dobj/0/colour1.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+obj/0/colour1.o: src/wstructs.h src/input.h src/rgb.h
+dobj/0/colour1.o: src/wstructs.h src/input.h src/rgb.h
+obj/0/colour2.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+dobj/0/colour2.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+obj/0/colour2.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+dobj/0/colour2.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+obj/0/colour2.o: src/wstructs.h src/input.h
+dobj/0/colour2.o: src/wstructs.h src/input.h
+obj/0/colour3.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+dobj/0/colour3.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+obj/0/colour3.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+dobj/0/colour3.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+obj/0/colour3.o: src/wstructs.h src/input.h src/rgb.h
+dobj/0/colour3.o: src/wstructs.h src/input.h src/rgb.h
+obj/0/colour4.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+dobj/0/colour4.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+obj/0/colour4.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+dobj/0/colour4.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+obj/0/colour4.o: src/wstructs.h src/input.h src/colour.h src/gfx.h src/rgb.h
+dobj/0/colour4.o: src/wstructs.h src/input.h src/colour.h src/gfx.h src/rgb.h
+obj/0/colour4.o: src/x11.h
+dobj/0/colour4.o: src/x11.h
+obj/0/dependcy.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+dobj/0/dependcy.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+obj/0/dependcy.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+dobj/0/dependcy.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+obj/0/dependcy.o: src/wstructs.h src/input.h src/dependcy.h src/serialnum.h
+dobj/0/dependcy.o: src/wstructs.h src/input.h src/dependcy.h src/serialnum.h
+obj/0/dialog.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+dobj/0/dialog.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+obj/0/dialog.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+dobj/0/dialog.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+obj/0/dialog.o: src/wstructs.h src/input.h src/dialog.h src/gfx.h
+dobj/0/dialog.o: src/wstructs.h src/input.h src/dialog.h src/gfx.h
+obj/0/disppic.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+dobj/0/disppic.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+obj/0/disppic.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+dobj/0/disppic.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+obj/0/disppic.o: src/wstructs.h src/input.h src/gfx.h src/imgspect.h
+dobj/0/disppic.o: src/wstructs.h src/input.h src/gfx.h src/imgspect.h
+obj/0/disppic.o: src/lists.h src/img.h src/patchdir.h src/pic2img.h
+dobj/0/disppic.o: src/lists.h src/img.h src/patchdir.h src/pic2img.h
+obj/0/disppic.o: src/sticker.h src/wadres.h src/spritdir.h src/lumpdir.h
+dobj/0/disppic.o: src/sticker.h src/wadres.h src/spritdir.h src/lumpdir.h
+obj/0/drawmap.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+dobj/0/drawmap.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+obj/0/drawmap.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+dobj/0/drawmap.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+obj/0/drawmap.o: src/wstructs.h src/input.h src/_edit.h src/objid.h
+dobj/0/drawmap.o: src/wstructs.h src/input.h src/_edit.h src/objid.h
+obj/0/drawmap.o: src/disppic.h src/lists.h src/img.h src/drawmap.h src/game.h
+dobj/0/drawmap.o: src/disppic.h src/lists.h src/img.h src/drawmap.h src/game.h
+obj/0/drawmap.o: src/rgb.h src/gfx.h src/imgscale.h src/imgspect.h src/levels.h
+dobj/0/drawmap.o: src/rgb.h src/gfx.h src/imgscale.h src/imgspect.h src/levels.h
+obj/0/drawmap.o: src/things.h src/pic2img.h src/s_centre.h src/sticker.h
+dobj/0/drawmap.o: src/things.h src/pic2img.h src/s_centre.h src/sticker.h
+obj/0/drawmap.o: src/vectext.h src/wadres.h src/spritdir.h src/lumpdir.h
+dobj/0/drawmap.o: src/vectext.h src/wadres.h src/spritdir.h src/lumpdir.h
+obj/0/edisplay.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+dobj/0/edisplay.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+obj/0/edisplay.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+dobj/0/edisplay.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+obj/0/edisplay.o: src/wstructs.h src/input.h src/_edit.h src/objid.h
+dobj/0/edisplay.o: src/wstructs.h src/input.h src/_edit.h src/objid.h
+obj/0/edisplay.o: src/drawmap.h src/edisplay.h src/editobj.h src/gfx.h
+dobj/0/edisplay.o: src/drawmap.h src/edisplay.h src/editobj.h src/gfx.h
+obj/0/edisplay.o: src/highlt.h src/edwidget.h src/infobar.h src/levels.h
+dobj/0/edisplay.o: src/highlt.h src/edwidget.h src/infobar.h src/levels.h
+obj/0/edisplay.o: src/things.h src/menu.h src/menubar.h src/modpopup.h
+dobj/0/edisplay.o: src/things.h src/menu.h src/menubar.h src/modpopup.h
+obj/0/edisplay.o: src/objects.h src/objinfo.h src/selbox.h src/spot.h
+dobj/0/edisplay.o: src/objects.h src/objinfo.h src/selbox.h src/spot.h
+obj/0/edisplay.o: src/wadfile.h
+dobj/0/edisplay.o: src/wadfile.h
+obj/0/editgrid.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+dobj/0/editgrid.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+obj/0/editgrid.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+dobj/0/editgrid.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+obj/0/editgrid.o: src/wstructs.h src/input.h src/_edit.h src/objid.h
+dobj/0/editgrid.o: src/wstructs.h src/input.h src/_edit.h src/objid.h
+obj/0/editgrid.o: src/editgrid.h
+dobj/0/editgrid.o: src/editgrid.h
+obj/0/editlev.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+dobj/0/editlev.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+obj/0/editlev.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+dobj/0/editlev.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+obj/0/editlev.o: src/wstructs.h src/input.h src/editlev.h src/editloop.h
+dobj/0/editlev.o: src/wstructs.h src/input.h src/editlev.h src/editloop.h
+obj/0/editlev.o: src/events.h src/game.h src/rgb.h src/gfx.h src/levels.h
+dobj/0/editlev.o: src/events.h src/game.h src/rgb.h src/gfx.h src/levels.h
+obj/0/editlev.o: src/things.h src/patchdir.h src/wadfile.h
+dobj/0/editlev.o: src/things.h src/patchdir.h src/wadfile.h
+obj/0/editloop.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+dobj/0/editloop.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+obj/0/editloop.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+dobj/0/editloop.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+obj/0/editloop.o: src/wstructs.h src/input.h src/_edit.h src/objid.h
+dobj/0/editloop.o: src/wstructs.h src/input.h src/_edit.h src/objid.h
+obj/0/editloop.o: src/checks.h src/dialog.h src/drawmap.h src/edisplay.h
+dobj/0/editloop.o: src/checks.h src/dialog.h src/drawmap.h src/edisplay.h
+obj/0/editloop.o: src/editgrid.h src/editloop.h src/editobj.h src/editsave.h
+dobj/0/editloop.o: src/editgrid.h src/editloop.h src/editobj.h src/editsave.h
+obj/0/editloop.o: src/editzoom.h src/entry.h src/entry2.h src/events.h
+dobj/0/editloop.o: src/editzoom.h src/entry.h src/entry2.h src/events.h
+obj/0/editloop.o: src/gfx.h src/gfx2.h src/gfx3.h src/rgbbmp.h src/gotoobj.h
+dobj/0/editloop.o: src/gfx.h src/gfx2.h src/gfx3.h src/rgbbmp.h src/gotoobj.h
+obj/0/editloop.o: src/help2.h src/l_flags.h src/levels.h src/things.h
+dobj/0/editloop.o: src/help2.h src/l_flags.h src/levels.h src/things.h
+obj/0/editloop.o: src/lists.h src/img.h src/menubar.h src/edwidget.h src/menu.h
+dobj/0/editloop.o: src/lists.h src/img.h src/menubar.h src/edwidget.h src/menu.h
+obj/0/editloop.o: src/modpopup.h src/objects.h src/palview.h src/prefer.h
+dobj/0/editloop.o: src/modpopup.h src/objects.h src/palview.h src/prefer.h
+obj/0/editloop.o: src/s_slice.h src/selbox.h src/selectn.h src/selpath.h
+dobj/0/editloop.o: src/s_slice.h src/selbox.h src/selectn.h src/selpath.h
+obj/0/editloop.o: src/spot.h src/t_flags.h src/t_spin.h src/x_centre.h
+dobj/0/editloop.o: src/spot.h src/t_flags.h src/t_spin.h src/x_centre.h
+obj/0/editloop.o: src/x_exchng.h src/x_hover.h src/xref.h
+dobj/0/editloop.o: src/x_exchng.h src/x_hover.h src/xref.h
+obj/0/editobj.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+dobj/0/editobj.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+obj/0/editobj.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+dobj/0/editobj.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+obj/0/editobj.o: src/wstructs.h src/input.h src/_edit.h src/objid.h
+dobj/0/editobj.o: src/wstructs.h src/input.h src/_edit.h src/objid.h
+obj/0/editobj.o: src/dialog.h src/editobj.h src/entry.h src/flats.h src/lists.h
+dobj/0/editobj.o: src/dialog.h src/editobj.h src/entry.h src/flats.h src/lists.h
+obj/0/editobj.o: src/img.h src/game.h src/rgb.h src/gfx.h src/levels.h
+dobj/0/editobj.o: src/img.h src/game.h src/rgb.h src/gfx.h src/levels.h
+obj/0/editobj.o: src/things.h src/objects.h src/oldmenus.h src/s_slice.h
+dobj/0/editobj.o: src/things.h src/objects.h src/oldmenus.h src/s_slice.h
+obj/0/editobj.o: src/s_swapf.h src/selectn.h src/t_spin.h src/x_mirror.h
+dobj/0/editobj.o: src/s_swapf.h src/selectn.h src/t_spin.h src/x_mirror.h
+obj/0/editobj.o: src/x_rotate.h
+dobj/0/editobj.o: src/x_rotate.h
+obj/0/editsave.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+dobj/0/editsave.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+obj/0/editsave.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+dobj/0/editsave.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+obj/0/editsave.o: src/wstructs.h src/input.h src/dialog.h src/editsave.h
+dobj/0/editsave.o: src/wstructs.h src/input.h src/dialog.h src/editsave.h
+obj/0/editsave.o: src/entry.h src/game.h src/rgb.h src/levels.h src/things.h
+dobj/0/editsave.o: src/entry.h src/game.h src/rgb.h src/levels.h src/things.h
+obj/0/editsave.o: src/wadfile.h src/wadlist.h
+dobj/0/editsave.o: src/wadfile.h src/wadlist.h
+obj/0/endian.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+dobj/0/endian.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+obj/0/endian.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+dobj/0/endian.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+obj/0/endian.o: src/wstructs.h src/input.h src/endian.h
+dobj/0/endian.o: src/wstructs.h src/input.h src/endian.h
+obj/0/editzoom.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+dobj/0/editzoom.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+obj/0/editzoom.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+dobj/0/editzoom.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+obj/0/editzoom.o: src/wstructs.h src/input.h src/_edit.h src/objid.h
+dobj/0/editzoom.o: src/wstructs.h src/input.h src/_edit.h src/objid.h
+obj/0/editzoom.o: src/editzoom.h src/events.h src/gfx.h
+dobj/0/editzoom.o: src/editzoom.h src/events.h src/gfx.h
+obj/0/entry.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+dobj/0/entry.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+obj/0/entry.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h src/wstructs.h
+dobj/0/entry.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h src/wstructs.h
+obj/0/entry.o: src/input.h src/entry.h src/gfx.h
+dobj/0/entry.o: src/input.h src/entry.h src/gfx.h
+obj/0/entry2.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+dobj/0/entry2.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+obj/0/entry2.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+dobj/0/entry2.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+obj/0/entry2.o: src/wstructs.h src/input.h src/entry2.h src/gfx.h
+dobj/0/entry2.o: src/wstructs.h src/input.h src/entry2.h src/gfx.h
+obj/0/events.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+dobj/0/events.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+obj/0/events.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+dobj/0/events.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+obj/0/events.o: src/wstructs.h src/input.h src/events.h
+dobj/0/events.o: src/wstructs.h src/input.h src/events.h
+obj/0/flats.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+dobj/0/flats.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+obj/0/flats.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h src/wstructs.h
+dobj/0/flats.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h src/wstructs.h
+obj/0/flats.o: src/input.h src/flats.h src/lists.h src/img.h src/gfx.h
+dobj/0/flats.o: src/input.h src/flats.h src/lists.h src/img.h src/gfx.h
+obj/0/flats.o: src/levels.h src/things.h src/sticker.h src/wadfile.h src/wads.h
+dobj/0/flats.o: src/levels.h src/things.h src/sticker.h src/wadfile.h src/wads.h
+obj/0/game.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+dobj/0/game.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+obj/0/game.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h src/wstructs.h
+dobj/0/game.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h src/wstructs.h
+obj/0/game.o: src/input.h src/acolours.h src/colour.h src/game.h src/rgb.h
+dobj/0/game.o: src/input.h src/acolours.h src/colour.h src/game.h src/rgb.h
+obj/0/game.o: src/gamesky.h src/wadname.h src/locate.h src/things.h src/trace.h
+dobj/0/game.o: src/gamesky.h src/wadname.h src/locate.h src/things.h src/trace.h
+obj/0/gcolour1.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+dobj/0/gcolour1.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+obj/0/gcolour1.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+dobj/0/gcolour1.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+obj/0/gcolour1.o: src/wstructs.h src/input.h src/gcolour1.h src/colour.h
+dobj/0/gcolour1.o: src/wstructs.h src/input.h src/gcolour1.h src/colour.h
+obj/0/gcolour1.o: src/gcolour2.h src/gfx.h src/img.h src/rgb.h src/wadfile.h
+dobj/0/gcolour1.o: src/gcolour2.h src/gfx.h src/img.h src/rgb.h src/wadfile.h
+obj/0/gcolour1.o: src/wads.h
+dobj/0/gcolour1.o: src/wads.h
+obj/0/gcolour2.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+dobj/0/gcolour2.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+obj/0/gcolour2.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+dobj/0/gcolour2.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+obj/0/gcolour2.o: src/wstructs.h src/input.h src/colour.h src/gcolour2.h
+dobj/0/gcolour2.o: src/wstructs.h src/input.h src/colour.h src/gcolour2.h
+obj/0/gcolour3.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+dobj/0/gcolour3.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+obj/0/gcolour3.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+dobj/0/gcolour3.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+obj/0/gcolour3.o: src/wstructs.h src/input.h src/colour.h src/gcolour3.h
+dobj/0/gcolour3.o: src/wstructs.h src/input.h src/colour.h src/gcolour3.h
+obj/0/geom.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+dobj/0/geom.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+obj/0/geom.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h src/wstructs.h
+dobj/0/geom.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h src/wstructs.h
+obj/0/geom.o: src/input.h
+dobj/0/geom.o: src/input.h
+obj/0/gfx.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h src/yerror.h
+dobj/0/gfx.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h src/yerror.h
+obj/0/gfx.o: src/ymemory.h src/aym.h src/windim.h src/wstructs.h src/input.h
+dobj/0/gfx.o: src/ymemory.h src/aym.h src/windim.h src/wstructs.h src/input.h
+obj/0/gfx.o: src/acolours.h src/colour.h src/gcolour1.h src/gcolour2.h
+dobj/0/gfx.o: src/acolours.h src/colour.h src/gcolour1.h src/gcolour2.h
+obj/0/gfx.o: src/gcolour3.h src/gfx.h src/levels.h src/things.h src/x11.h
+dobj/0/gfx.o: src/gcolour3.h src/gfx.h src/levels.h src/things.h src/x11.h
+obj/0/gfx2.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+dobj/0/gfx2.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+obj/0/gfx2.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h src/wstructs.h
+dobj/0/gfx2.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h src/wstructs.h
+obj/0/gfx2.o: src/input.h src/colour.h src/gcolour2.h src/gfx.h src/rgb.h
+dobj/0/gfx2.o: src/input.h src/colour.h src/gcolour2.h src/gfx.h src/rgb.h
+obj/0/gfx3.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+dobj/0/gfx3.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+obj/0/gfx3.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h src/wstructs.h
+dobj/0/gfx3.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h src/wstructs.h
+obj/0/gfx3.o: src/input.h src/colour.h src/gfx.h src/gfx3.h src/rgbbmp.h
+dobj/0/gfx3.o: src/input.h src/colour.h src/gfx.h src/gfx3.h src/rgbbmp.h
+obj/0/gotoobj.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+dobj/0/gotoobj.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+obj/0/gotoobj.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+dobj/0/gotoobj.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+obj/0/gotoobj.o: src/wstructs.h src/input.h src/gfx.h src/gotoobj.h
+dobj/0/gotoobj.o: src/wstructs.h src/input.h src/gfx.h src/gotoobj.h
+obj/0/gotoobj.o: src/levels.h src/things.h src/objects.h src/objid.h
+dobj/0/gotoobj.o: src/levels.h src/things.h src/objects.h src/objid.h
+obj/0/gotoobj.o: src/x_hover.h
+dobj/0/gotoobj.o: src/x_hover.h
+obj/0/help1.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+dobj/0/help1.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+obj/0/help1.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h src/wstructs.h
+dobj/0/help1.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h src/wstructs.h
+obj/0/help1.o: src/input.h src/cfgfile.h src/help1.h
+dobj/0/help1.o: src/input.h src/cfgfile.h src/help1.h
+obj/0/help2.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+dobj/0/help2.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+obj/0/help2.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h src/wstructs.h
+dobj/0/help2.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h src/wstructs.h
+obj/0/help2.o: src/input.h src/credits.h src/gfx.h src/help1.h src/help2.h
+dobj/0/help2.o: src/input.h src/credits.h src/gfx.h src/help1.h src/help2.h
+obj/0/highlt.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+dobj/0/highlt.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+obj/0/highlt.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+dobj/0/highlt.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+obj/0/highlt.o: src/wstructs.h src/input.h src/highlt.h src/edwidget.h
+dobj/0/highlt.o: src/wstructs.h src/input.h src/highlt.h src/edwidget.h
+obj/0/highlt.o: src/objid.h src/objects.h
+dobj/0/highlt.o: src/objid.h src/objects.h
+obj/0/img.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h src/yerror.h
+dobj/0/img.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h src/yerror.h
+obj/0/img.o: src/ymemory.h src/aym.h src/windim.h src/wstructs.h src/input.h
+dobj/0/img.o: src/ymemory.h src/aym.h src/windim.h src/wstructs.h src/input.h
+obj/0/img.o: src/help1.h src/img.h src/wadfile.h src/wads.h
+dobj/0/img.o: src/help1.h src/img.h src/wadfile.h src/wads.h
+obj/0/imgscale.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+dobj/0/imgscale.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+obj/0/imgscale.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+dobj/0/imgscale.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+obj/0/imgscale.o: src/wstructs.h src/input.h src/img.h
+dobj/0/imgscale.o: src/wstructs.h src/input.h src/img.h
+obj/0/imgspect.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+dobj/0/imgspect.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+obj/0/imgspect.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+dobj/0/imgspect.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+obj/0/imgspect.o: src/wstructs.h src/input.h src/img.h src/imgspect.h
+dobj/0/imgspect.o: src/wstructs.h src/input.h src/img.h src/imgspect.h
+obj/0/infobar.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+dobj/0/infobar.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+obj/0/infobar.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+dobj/0/infobar.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+obj/0/infobar.o: src/wstructs.h src/input.h src/gfx.h src/infobar.h
+dobj/0/infobar.o: src/wstructs.h src/input.h src/gfx.h src/infobar.h
+obj/0/infobar.o: src/edwidget.h src/objid.h
+dobj/0/infobar.o: src/edwidget.h src/objid.h
+obj/0/input.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+dobj/0/input.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+obj/0/input.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h src/wstructs.h
+dobj/0/input.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h src/wstructs.h
+obj/0/input.o: src/input.h src/gfx.h
+dobj/0/input.o: src/input.h src/gfx.h
+obj/0/l_align.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+dobj/0/l_align.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+obj/0/l_align.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+dobj/0/l_align.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+obj/0/l_align.o: src/wstructs.h src/input.h src/dialog.h src/entry.h src/gfx.h
+dobj/0/l_align.o: src/wstructs.h src/input.h src/dialog.h src/entry.h src/gfx.h
+obj/0/l_align.o: src/levels.h src/things.h src/objid.h src/oldmenus.h
+dobj/0/l_align.o: src/levels.h src/things.h src/objid.h src/oldmenus.h
+obj/0/l_align.o: src/selectn.h src/textures.h src/lists.h src/img.h
+dobj/0/l_align.o: src/selectn.h src/textures.h src/lists.h src/img.h
+obj/0/l_centre.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+dobj/0/l_centre.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+obj/0/l_centre.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+dobj/0/l_centre.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+obj/0/l_centre.o: src/wstructs.h src/input.h src/l_centre.h src/l_vertices.h
+dobj/0/l_centre.o: src/wstructs.h src/input.h src/l_centre.h src/l_vertices.h
+obj/0/l_centre.o: src/selectn.h src/levels.h src/things.h
+dobj/0/l_centre.o: src/selectn.h src/levels.h src/things.h
+obj/0/l_flags.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+dobj/0/l_flags.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+obj/0/l_flags.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+dobj/0/l_flags.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+obj/0/l_flags.o: src/wstructs.h src/input.h src/levels.h src/things.h
+dobj/0/l_flags.o: src/wstructs.h src/input.h src/levels.h src/things.h
+obj/0/l_flags.o: src/selectn.h
+dobj/0/l_flags.o: src/selectn.h
+obj/0/l_misc.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+dobj/0/l_misc.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+obj/0/l_misc.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+dobj/0/l_misc.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+obj/0/l_misc.o: src/wstructs.h src/input.h src/levels.h src/things.h
+dobj/0/l_misc.o: src/wstructs.h src/input.h src/levels.h src/things.h
+obj/0/l_misc.o: src/objects.h src/objid.h src/selectn.h
+dobj/0/l_misc.o: src/objects.h src/objid.h src/selectn.h
+obj/0/l_prop.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+dobj/0/l_prop.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+obj/0/l_prop.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+dobj/0/l_prop.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+obj/0/l_prop.o: src/wstructs.h src/input.h src/entry.h src/gfx.h src/levels.h
+dobj/0/l_prop.o: src/wstructs.h src/input.h src/entry.h src/gfx.h src/levels.h
+obj/0/l_prop.o: src/things.h src/menudata.h src/objects.h src/objid.h
+dobj/0/l_prop.o: src/things.h src/menudata.h src/objects.h src/objid.h
+obj/0/l_prop.o: src/oldmenus.h src/game.h src/rgb.h src/selectn.h
+dobj/0/l_prop.o: src/oldmenus.h src/game.h src/rgb.h src/selectn.h
+obj/0/l_prop.o: src/textures.h src/lists.h src/img.h
+dobj/0/l_prop.o: src/textures.h src/lists.h src/img.h
+obj/0/l_unlink.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+dobj/0/l_unlink.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+obj/0/l_unlink.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+dobj/0/l_unlink.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+obj/0/l_unlink.o: src/wstructs.h src/input.h src/levels.h src/things.h
+dobj/0/l_unlink.o: src/wstructs.h src/input.h src/levels.h src/things.h
+obj/0/l_unlink.o: src/objects.h src/objid.h src/selectn.h
+dobj/0/l_unlink.o: src/objects.h src/objid.h src/selectn.h
+obj/0/l_vertices.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+dobj/0/l_vertices.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+obj/0/l_vertices.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+dobj/0/l_vertices.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+obj/0/l_vertices.o: src/wstructs.h src/input.h src/l_vertices.h src/selectn.h
+dobj/0/l_vertices.o: src/wstructs.h src/input.h src/l_vertices.h src/selectn.h
+obj/0/l_vertices.o: src/levels.h src/things.h
+dobj/0/l_vertices.o: src/levels.h src/things.h
+obj/0/levels.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+dobj/0/levels.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+obj/0/levels.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+dobj/0/levels.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+obj/0/levels.o: src/wstructs.h src/input.h src/dialog.h src/game.h src/rgb.h
+dobj/0/levels.o: src/wstructs.h src/input.h src/dialog.h src/game.h src/rgb.h
+obj/0/levels.o: src/levels.h src/things.h src/objid.h src/wadfile.h src/wads.h
+dobj/0/levels.o: src/levels.h src/things.h src/objid.h src/wadfile.h src/wads.h
+obj/0/levels.o: src/wads2.h
+dobj/0/levels.o: src/wads2.h
+obj/0/lists.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+dobj/0/lists.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+obj/0/lists.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h src/wstructs.h
+dobj/0/lists.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h src/wstructs.h
+obj/0/lists.o: src/input.h src/gfx.h src/lists.h src/img.h src/wadfile.h
+dobj/0/lists.o: src/input.h src/gfx.h src/lists.h src/img.h src/wadfile.h
+obj/0/locate.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+dobj/0/locate.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+obj/0/locate.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+dobj/0/locate.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+obj/0/locate.o: src/wstructs.h src/input.h src/locate.h src/macro.h src/trace.h
+dobj/0/locate.o: src/wstructs.h src/input.h src/locate.h src/macro.h src/trace.h
+obj/0/lumpdir.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+dobj/0/lumpdir.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+obj/0/lumpdir.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+dobj/0/lumpdir.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+obj/0/lumpdir.o: src/wstructs.h src/input.h src/dependcy.h src/lumpdir.h
+dobj/0/lumpdir.o: src/wstructs.h src/input.h src/dependcy.h src/lumpdir.h
+obj/0/lumpdir.o: src/wadname.h src/wadnamec.h src/wadfile.h
+dobj/0/lumpdir.o: src/wadname.h src/wadnamec.h src/wadfile.h
+obj/0/macro.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+dobj/0/macro.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+obj/0/macro.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h src/wstructs.h
+dobj/0/macro.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h src/wstructs.h
+obj/0/macro.o: src/input.h src/macro.h
+dobj/0/macro.o: src/input.h src/macro.h
+obj/0/memory.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+dobj/0/memory.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+obj/0/memory.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+dobj/0/memory.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+obj/0/memory.o: src/wstructs.h src/input.h
+dobj/0/memory.o: src/wstructs.h src/input.h
+obj/0/menubar.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+dobj/0/menubar.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+obj/0/menubar.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+dobj/0/menubar.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+obj/0/menubar.o: src/wstructs.h src/input.h src/gfx.h src/menubar.h
+dobj/0/menubar.o: src/wstructs.h src/input.h src/gfx.h src/menubar.h
+obj/0/menubar.o: src/edwidget.h src/menu.h
+dobj/0/menubar.o: src/edwidget.h src/menu.h
+obj/0/menu.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+dobj/0/menu.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+obj/0/menu.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h src/wstructs.h
+dobj/0/menu.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h src/wstructs.h
+obj/0/menu.o: src/input.h src/events.h src/gfx.h src/menu.h src/edwidget.h
+dobj/0/menu.o: src/input.h src/events.h src/gfx.h src/menu.h src/edwidget.h
+obj/0/menu.o: src/menudata.h
+dobj/0/menu.o: src/menudata.h
+obj/0/mkpalette.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+dobj/0/mkpalette.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+obj/0/mkpalette.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+dobj/0/mkpalette.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+obj/0/mkpalette.o: src/wstructs.h src/input.h src/mkpalette.h src/gfx.h
+dobj/0/mkpalette.o: src/wstructs.h src/input.h src/mkpalette.h src/gfx.h
+obj/0/mkpalette.o: src/rgb.h src/wadfile.h src/wads.h
+dobj/0/mkpalette.o: src/rgb.h src/wadfile.h src/wads.h
+obj/0/mouse.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+dobj/0/mouse.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+obj/0/mouse.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h src/wstructs.h
+dobj/0/mouse.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h src/wstructs.h
+obj/0/mouse.o: src/input.h
+dobj/0/mouse.o: src/input.h
+obj/0/names.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+dobj/0/names.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+obj/0/names.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h src/wstructs.h
+dobj/0/names.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h src/wstructs.h
+obj/0/names.o: src/input.h src/game.h src/rgb.h src/objid.h
+dobj/0/names.o: src/input.h src/game.h src/rgb.h src/objid.h
+obj/0/nop.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h src/yerror.h
+dobj/0/nop.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h src/yerror.h
+obj/0/nop.o: src/ymemory.h src/aym.h src/windim.h src/wstructs.h src/input.h
+dobj/0/nop.o: src/ymemory.h src/aym.h src/windim.h src/wstructs.h src/input.h
+obj/0/objects.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+dobj/0/objects.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+obj/0/objects.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+dobj/0/objects.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+obj/0/objects.o: src/wstructs.h src/input.h src/drawmap.h src/_edit.h
+dobj/0/objects.o: src/wstructs.h src/input.h src/drawmap.h src/_edit.h
+obj/0/objects.o: src/objid.h src/gfx.h src/l_vertices.h src/selectn.h
+dobj/0/objects.o: src/objid.h src/gfx.h src/l_vertices.h src/selectn.h
+obj/0/objects.o: src/levels.h src/things.h src/objects.h src/s_vertices.h
+dobj/0/objects.o: src/levels.h src/things.h src/objects.h src/s_vertices.h
+obj/0/objinfo.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+dobj/0/objinfo.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+obj/0/objinfo.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+dobj/0/objinfo.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+obj/0/objinfo.o: src/wstructs.h src/input.h src/disppic.h src/lists.h src/img.h
+dobj/0/objinfo.o: src/wstructs.h src/input.h src/disppic.h src/lists.h src/img.h
+obj/0/objinfo.o: src/flats.h src/game.h src/rgb.h src/gamesky.h src/wadname.h
+dobj/0/objinfo.o: src/flats.h src/game.h src/rgb.h src/gamesky.h src/wadname.h
+obj/0/objinfo.o: src/gfx.h src/imgspect.h src/l_super.h src/levels.h
+dobj/0/objinfo.o: src/gfx.h src/imgspect.h src/l_super.h src/levels.h
+obj/0/objinfo.o: src/things.h src/objid.h src/objinfo.h src/edwidget.h
+dobj/0/objinfo.o: src/things.h src/objid.h src/objinfo.h src/edwidget.h
+obj/0/objinfo.o: src/pic2img.h src/sticker.h src/wadres.h src/spritdir.h
+dobj/0/objinfo.o: src/pic2img.h src/sticker.h src/wadres.h src/spritdir.h
+obj/0/objinfo.o: src/lumpdir.h
+dobj/0/objinfo.o: src/lumpdir.h
+obj/0/oldmenus.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+dobj/0/oldmenus.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+obj/0/oldmenus.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+dobj/0/oldmenus.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+obj/0/oldmenus.o: src/wstructs.h src/input.h src/events.h src/gfx.h src/menu.h
+dobj/0/oldmenus.o: src/wstructs.h src/input.h src/events.h src/gfx.h src/menu.h
+obj/0/oldmenus.o: src/edwidget.h src/oldmenus.h
+dobj/0/oldmenus.o: src/edwidget.h src/oldmenus.h
+obj/0/palview.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+dobj/0/palview.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+obj/0/palview.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+dobj/0/palview.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+obj/0/palview.o: src/wstructs.h src/input.h src/colour.h src/gcolour2.h
+dobj/0/palview.o: src/wstructs.h src/input.h src/colour.h src/gcolour2.h
+obj/0/palview.o: src/gfx.h src/palview.h src/rgb.h src/wadfile.h src/wads.h
+dobj/0/palview.o: src/gfx.h src/palview.h src/rgb.h src/wadfile.h src/wads.h
+obj/0/palview.o: src/ytime.h
+dobj/0/palview.o: src/ytime.h
+obj/0/patchdir.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+dobj/0/patchdir.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+obj/0/patchdir.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+dobj/0/patchdir.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+obj/0/patchdir.o: src/wstructs.h src/input.h src/patchdir.h src/wadfile.h
+dobj/0/patchdir.o: src/wstructs.h src/input.h src/patchdir.h src/wadfile.h
+obj/0/patchdir.o: src/wads.h
+dobj/0/patchdir.o: src/wads.h
+obj/0/pic2img.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+dobj/0/pic2img.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+obj/0/pic2img.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+dobj/0/pic2img.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+obj/0/pic2img.o: src/wstructs.h src/input.h src/gcolour2.h src/colour.h
+dobj/0/pic2img.o: src/wstructs.h src/input.h src/gcolour2.h src/colour.h
+obj/0/pic2img.o: src/pic2img.h src/img.h src/wadfile.h src/wads.h
+dobj/0/pic2img.o: src/pic2img.h src/img.h src/wadfile.h src/wads.h
+obj/0/prefer.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+dobj/0/prefer.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+obj/0/prefer.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+dobj/0/prefer.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+obj/0/prefer.o: src/wstructs.h src/input.h src/entry.h src/flats.h src/lists.h
+dobj/0/prefer.o: src/wstructs.h src/input.h src/entry.h src/flats.h src/lists.h
+obj/0/prefer.o: src/img.h src/gfx.h src/levels.h src/things.h src/oldmenus.h
+dobj/0/prefer.o: src/img.h src/gfx.h src/levels.h src/things.h src/oldmenus.h
+obj/0/prefer.o: src/prefer.h src/textures.h
+dobj/0/prefer.o: src/prefer.h src/textures.h
+obj/0/s_centre.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+dobj/0/s_centre.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+obj/0/s_centre.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+dobj/0/s_centre.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+obj/0/s_centre.o: src/wstructs.h src/input.h src/levels.h src/things.h
+dobj/0/s_centre.o: src/wstructs.h src/input.h src/levels.h src/things.h
+obj/0/s_centre.o: src/s_centre.h src/objid.h src/s_vertices.h src/selectn.h
+dobj/0/s_centre.o: src/s_centre.h src/objid.h src/s_vertices.h src/selectn.h
+obj/0/s_door.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+dobj/0/s_door.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+obj/0/s_door.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+dobj/0/s_door.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+obj/0/s_door.o: src/wstructs.h src/input.h src/dialog.h src/levels.h
+dobj/0/s_door.o: src/wstructs.h src/input.h src/dialog.h src/levels.h
+obj/0/s_door.o: src/things.h src/objid.h src/selectn.h
+dobj/0/s_door.o: src/things.h src/objid.h src/selectn.h
+obj/0/s_lift.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+dobj/0/s_lift.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+obj/0/s_lift.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+dobj/0/s_lift.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+obj/0/s_lift.o: src/wstructs.h src/input.h src/dialog.h src/levels.h
+dobj/0/s_lift.o: src/wstructs.h src/input.h src/dialog.h src/levels.h
+obj/0/s_lift.o: src/things.h src/objects.h src/objid.h src/selectn.h
+dobj/0/s_lift.o: src/things.h src/objects.h src/objid.h src/selectn.h
+obj/0/s_linedefs.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+dobj/0/s_linedefs.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+obj/0/s_linedefs.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+dobj/0/s_linedefs.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+obj/0/s_linedefs.o: src/wstructs.h src/input.h src/levels.h src/things.h
+dobj/0/s_linedefs.o: src/wstructs.h src/input.h src/levels.h src/things.h
+obj/0/s_linedefs.o: src/objects.h src/objid.h src/s_linedefs.h src/selectn.h
+dobj/0/s_linedefs.o: src/objects.h src/objid.h src/s_linedefs.h src/selectn.h
+obj/0/s_merge.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+dobj/0/s_merge.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+obj/0/s_merge.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+dobj/0/s_merge.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+obj/0/s_merge.o: src/wstructs.h src/input.h src/dialog.h src/levels.h
+dobj/0/s_merge.o: src/wstructs.h src/input.h src/dialog.h src/levels.h
+obj/0/s_merge.o: src/things.h src/objects.h src/objid.h src/selectn.h
+dobj/0/s_merge.o: src/things.h src/objects.h src/objid.h src/selectn.h
+obj/0/s_misc.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+dobj/0/s_misc.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+obj/0/s_misc.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+dobj/0/s_misc.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+obj/0/s_misc.o: src/wstructs.h src/input.h src/entry.h src/gfx.h src/levels.h
+dobj/0/s_misc.o: src/wstructs.h src/input.h src/entry.h src/gfx.h src/levels.h
+obj/0/s_misc.o: src/things.h src/objid.h src/selectn.h
+dobj/0/s_misc.o: src/things.h src/objid.h src/selectn.h
+obj/0/s_prop.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+dobj/0/s_prop.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+obj/0/s_prop.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+dobj/0/s_prop.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+obj/0/s_prop.o: src/wstructs.h src/input.h src/entry.h src/flats.h src/lists.h
+dobj/0/s_prop.o: src/wstructs.h src/input.h src/entry.h src/flats.h src/lists.h
+obj/0/s_prop.o: src/img.h src/game.h src/rgb.h src/gfx.h src/levels.h
+dobj/0/s_prop.o: src/img.h src/game.h src/rgb.h src/gfx.h src/levels.h
+obj/0/s_prop.o: src/things.h src/menudata.h src/objid.h src/oldmenus.h
+dobj/0/s_prop.o: src/things.h src/menudata.h src/objid.h src/oldmenus.h
+obj/0/s_prop.o: src/selectn.h
+dobj/0/s_prop.o: src/selectn.h
+obj/0/s_slice.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+dobj/0/s_slice.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+obj/0/s_slice.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+dobj/0/s_slice.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+obj/0/s_slice.o: src/wstructs.h src/input.h src/dialog.h src/levels.h
+dobj/0/s_slice.o: src/wstructs.h src/input.h src/dialog.h src/levels.h
+obj/0/s_slice.o: src/things.h src/objects.h src/objid.h src/s_slice.h
+dobj/0/s_slice.o: src/things.h src/objects.h src/objid.h src/s_slice.h
+obj/0/s_split.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+dobj/0/s_split.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+obj/0/s_split.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+dobj/0/s_split.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+obj/0/s_split.o: src/wstructs.h src/input.h src/dialog.h src/levels.h
+dobj/0/s_split.o: src/wstructs.h src/input.h src/dialog.h src/levels.h
+obj/0/s_split.o: src/things.h src/objects.h src/objid.h src/s_linedefs.h
+dobj/0/s_split.o: src/things.h src/objects.h src/objid.h src/s_linedefs.h
+obj/0/s_split.o: src/selectn.h src/x_hover.h
+dobj/0/s_split.o: src/selectn.h src/x_hover.h
+obj/0/s_swapf.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+dobj/0/s_swapf.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+obj/0/s_swapf.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+dobj/0/s_swapf.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+obj/0/s_swapf.o: src/wstructs.h src/input.h src/levels.h src/things.h
+dobj/0/s_swapf.o: src/wstructs.h src/input.h src/levels.h src/things.h
+obj/0/s_swapf.o: src/selectn.h
+dobj/0/s_swapf.o: src/selectn.h
+obj/0/s_vertices.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+dobj/0/s_vertices.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+obj/0/s_vertices.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+dobj/0/s_vertices.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+obj/0/s_vertices.o: src/wstructs.h src/input.h src/l_vertices.h src/selectn.h
+dobj/0/s_vertices.o: src/wstructs.h src/input.h src/l_vertices.h src/selectn.h
+obj/0/s_vertices.o: src/levels.h src/things.h src/objid.h src/s_linedefs.h
+dobj/0/s_vertices.o: src/levels.h src/things.h src/objid.h src/s_linedefs.h
+obj/0/s_vertices.o: src/s_vertices.h
+dobj/0/s_vertices.o: src/s_vertices.h
+obj/0/sanity.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+dobj/0/sanity.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+obj/0/sanity.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+dobj/0/sanity.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+obj/0/sanity.o: src/wstructs.h src/input.h src/sanity.h
+dobj/0/sanity.o: src/wstructs.h src/input.h src/sanity.h
+obj/0/scrnshot.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+dobj/0/scrnshot.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+obj/0/scrnshot.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+dobj/0/scrnshot.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+obj/0/scrnshot.o: src/wstructs.h src/input.h
+dobj/0/scrnshot.o: src/wstructs.h src/input.h
+obj/0/selbox.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+dobj/0/selbox.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+obj/0/selbox.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+dobj/0/selbox.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+obj/0/selbox.o: src/wstructs.h src/input.h src/gfx.h src/selbox.h
+dobj/0/selbox.o: src/wstructs.h src/input.h src/gfx.h src/selbox.h
+obj/0/selbox.o: src/edwidget.h
+dobj/0/selbox.o: src/edwidget.h
+obj/0/selectn.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+dobj/0/selectn.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+obj/0/selectn.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+dobj/0/selectn.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+obj/0/selectn.o: src/wstructs.h src/input.h src/objid.h src/selectn.h
+dobj/0/selectn.o: src/wstructs.h src/input.h src/objid.h src/selectn.h
+obj/0/selpath.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+dobj/0/selpath.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+obj/0/selpath.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+dobj/0/selpath.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+obj/0/selpath.o: src/wstructs.h src/input.h src/levels.h src/things.h
+dobj/0/selpath.o: src/wstructs.h src/input.h src/levels.h src/things.h
+obj/0/selpath.o: src/objid.h src/selectn.h
+dobj/0/selpath.o: src/objid.h src/selectn.h
+obj/0/selrect.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+dobj/0/selrect.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+obj/0/selrect.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+dobj/0/selrect.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+obj/0/selrect.o: src/wstructs.h src/input.h src/levels.h src/things.h
+dobj/0/selrect.o: src/wstructs.h src/input.h src/levels.h src/things.h
+obj/0/selrect.o: src/objid.h src/selectn.h
+dobj/0/selrect.o: src/objid.h src/selectn.h
+obj/0/serialnum.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+dobj/0/serialnum.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+obj/0/serialnum.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+dobj/0/serialnum.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+obj/0/serialnum.o: src/wstructs.h src/input.h src/serialnum.h
+dobj/0/serialnum.o: src/wstructs.h src/input.h src/serialnum.h
+obj/0/spritdir.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+dobj/0/spritdir.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+obj/0/spritdir.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+dobj/0/spritdir.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+obj/0/spritdir.o: src/wstructs.h src/input.h src/dependcy.h src/lumpdir.h
+dobj/0/spritdir.o: src/wstructs.h src/input.h src/dependcy.h src/lumpdir.h
+obj/0/spritdir.o: src/spritdir.h src/wadname.h src/wadnamec.h
+dobj/0/spritdir.o: src/spritdir.h src/wadname.h src/wadnamec.h
+obj/0/sticker.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+dobj/0/sticker.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+obj/0/sticker.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+dobj/0/sticker.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+obj/0/sticker.o: src/wstructs.h src/input.h src/gcolour2.h src/colour.h
+dobj/0/sticker.o: src/wstructs.h src/input.h src/gcolour2.h src/colour.h
+obj/0/sticker.o: src/gcolour3.h src/gfx.h src/img.h src/sticker.h
+dobj/0/sticker.o: src/gcolour3.h src/gfx.h src/img.h src/sticker.h
+obj/0/swapmem.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+dobj/0/swapmem.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+obj/0/swapmem.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+dobj/0/swapmem.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+obj/0/swapmem.o: src/wstructs.h src/input.h src/levels.h src/things.h
+dobj/0/swapmem.o: src/wstructs.h src/input.h src/levels.h src/things.h
+obj/0/swapmem.o: src/objid.h
+dobj/0/swapmem.o: src/objid.h
+obj/0/t_centre.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+dobj/0/t_centre.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+obj/0/t_centre.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+dobj/0/t_centre.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+obj/0/t_centre.o: src/wstructs.h src/input.h src/levels.h src/things.h
+dobj/0/t_centre.o: src/wstructs.h src/input.h src/levels.h src/things.h
+obj/0/t_centre.o: src/selectn.h src/t_centre.h
+dobj/0/t_centre.o: src/selectn.h src/t_centre.h
+obj/0/t_flags.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+dobj/0/t_flags.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+obj/0/t_flags.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+dobj/0/t_flags.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+obj/0/t_flags.o: src/wstructs.h src/input.h src/levels.h src/things.h
+dobj/0/t_flags.o: src/wstructs.h src/input.h src/levels.h src/things.h
+obj/0/t_flags.o: src/selectn.h
+dobj/0/t_flags.o: src/selectn.h
+obj/0/t_prop.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+dobj/0/t_prop.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+obj/0/t_prop.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+dobj/0/t_prop.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+obj/0/t_prop.o: src/wstructs.h src/input.h src/entry.h src/game.h src/rgb.h
+dobj/0/t_prop.o: src/wstructs.h src/input.h src/entry.h src/game.h src/rgb.h
+obj/0/t_prop.o: src/gfx.h src/levels.h src/things.h src/oldmenus.h
+dobj/0/t_prop.o: src/gfx.h src/levels.h src/things.h src/oldmenus.h
+obj/0/t_prop.o: src/selectn.h
+dobj/0/t_prop.o: src/selectn.h
+obj/0/t_spin.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+dobj/0/t_spin.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+obj/0/t_spin.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+dobj/0/t_spin.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+obj/0/t_spin.o: src/wstructs.h src/input.h src/levels.h src/things.h
+dobj/0/t_spin.o: src/wstructs.h src/input.h src/levels.h src/things.h
+obj/0/t_spin.o: src/selectn.h src/t_spin.h
+dobj/0/t_spin.o: src/selectn.h src/t_spin.h
+obj/0/textures.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+dobj/0/textures.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+obj/0/textures.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+dobj/0/textures.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+obj/0/textures.o: src/wstructs.h src/input.h src/dialog.h src/game.h src/rgb.h
+dobj/0/textures.o: src/wstructs.h src/input.h src/dialog.h src/game.h src/rgb.h
+obj/0/textures.o: src/gfx.h src/lists.h src/img.h src/patchdir.h src/pic2img.h
+dobj/0/textures.o: src/gfx.h src/lists.h src/img.h src/patchdir.h src/pic2img.h
+obj/0/textures.o: src/sticker.h src/textures.h src/wadfile.h src/wads.h
+dobj/0/textures.o: src/sticker.h src/textures.h src/wadfile.h src/wads.h
+obj/0/things.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+dobj/0/things.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+obj/0/things.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+dobj/0/things.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+obj/0/things.o: src/wstructs.h src/input.h src/game.h src/rgb.h src/things.h
+dobj/0/things.o: src/wstructs.h src/input.h src/game.h src/rgb.h src/things.h
+obj/0/trace.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+dobj/0/trace.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+obj/0/trace.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h src/wstructs.h
+dobj/0/trace.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h src/wstructs.h
+obj/0/trace.o: src/input.h src/trace.h
+dobj/0/trace.o: src/input.h src/trace.h
+obj/0/v_centre.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+dobj/0/v_centre.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+obj/0/v_centre.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+dobj/0/v_centre.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+obj/0/v_centre.o: src/wstructs.h src/input.h src/levels.h src/things.h
+dobj/0/v_centre.o: src/wstructs.h src/input.h src/levels.h src/things.h
+obj/0/v_centre.o: src/selectn.h src/v_centre.h
+dobj/0/v_centre.o: src/selectn.h src/v_centre.h
+obj/0/v_merge.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+dobj/0/v_merge.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+obj/0/v_merge.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+dobj/0/v_merge.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+obj/0/v_merge.o: src/wstructs.h src/input.h src/dialog.h src/levels.h
+dobj/0/v_merge.o: src/wstructs.h src/input.h src/dialog.h src/levels.h
+obj/0/v_merge.o: src/things.h src/objects.h src/objid.h src/selectn.h
+dobj/0/v_merge.o: src/things.h src/objects.h src/objid.h src/selectn.h
+obj/0/v_polyg.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+dobj/0/v_polyg.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+obj/0/v_polyg.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+dobj/0/v_polyg.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+obj/0/v_polyg.o: src/wstructs.h src/input.h src/objects.h src/objid.h
+dobj/0/v_polyg.o: src/wstructs.h src/input.h src/objects.h src/objid.h
+obj/0/vectext.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+dobj/0/vectext.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+obj/0/vectext.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+dobj/0/vectext.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+obj/0/vectext.o: src/wstructs.h src/input.h src/gfx.h src/vectext.h
+dobj/0/vectext.o: src/wstructs.h src/input.h src/gfx.h src/vectext.h
+obj/0/verbmsg.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+dobj/0/verbmsg.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+obj/0/verbmsg.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+dobj/0/verbmsg.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+obj/0/verbmsg.o: src/wstructs.h src/input.h
+dobj/0/verbmsg.o: src/wstructs.h src/input.h
+obj/0/wadfile.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+dobj/0/wadfile.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+obj/0/wadfile.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+dobj/0/wadfile.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+obj/0/wadfile.o: src/wstructs.h src/input.h src/wadfile.h
+dobj/0/wadfile.o: src/wstructs.h src/input.h src/wadfile.h
+obj/0/wadlist.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+dobj/0/wadlist.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+obj/0/wadlist.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+dobj/0/wadlist.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+obj/0/wadlist.o: src/wstructs.h src/input.h src/wadfile.h src/wadlist.h
+dobj/0/wadlist.o: src/wstructs.h src/input.h src/wadfile.h src/wadlist.h
+obj/0/wadnamec.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+dobj/0/wadnamec.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+obj/0/wadnamec.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+dobj/0/wadnamec.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+obj/0/wadnamec.o: src/wstructs.h src/input.h src/wadnamec.h
+dobj/0/wadnamec.o: src/wstructs.h src/input.h src/wadnamec.h
+obj/0/wadres.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+dobj/0/wadres.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+obj/0/wadres.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+dobj/0/wadres.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+obj/0/wadres.o: src/wstructs.h src/input.h src/wadres.h src/spritdir.h
+dobj/0/wadres.o: src/wstructs.h src/input.h src/wadres.h src/spritdir.h
+obj/0/wadres.o: src/lumpdir.h
+dobj/0/wadres.o: src/lumpdir.h
+obj/0/wads.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+dobj/0/wads.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+obj/0/wads.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h src/wstructs.h
+dobj/0/wads.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h src/wstructs.h
+obj/0/wads.o: src/input.h src/serialnum.h src/wads.h
+dobj/0/wads.o: src/input.h src/serialnum.h src/wads.h
+obj/0/wads2.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+dobj/0/wads2.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+obj/0/wads2.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h src/wstructs.h
+dobj/0/wads2.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h src/wstructs.h
+obj/0/wads2.o: src/input.h src/game.h src/rgb.h src/serialnum.h src/wadfile.h
+dobj/0/wads2.o: src/input.h src/game.h src/rgb.h src/serialnum.h src/wadfile.h
+obj/0/wads2.o: src/wadlist.h src/wads.h src/wads2.h
+dobj/0/wads2.o: src/wadlist.h src/wads.h src/wads2.h
+obj/0/warn.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+dobj/0/warn.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+obj/0/warn.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h src/wstructs.h
+dobj/0/warn.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h src/wstructs.h
+obj/0/warn.o: src/input.h
+dobj/0/warn.o: src/input.h
+obj/0/windim.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+dobj/0/windim.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+obj/0/windim.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+dobj/0/windim.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+obj/0/windim.o: src/wstructs.h src/input.h
+dobj/0/windim.o: src/wstructs.h src/input.h
+obj/0/x_centre.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+dobj/0/x_centre.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+obj/0/x_centre.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+dobj/0/x_centre.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+obj/0/x_centre.o: src/wstructs.h src/input.h src/l_centre.h src/levels.h
+dobj/0/x_centre.o: src/wstructs.h src/input.h src/l_centre.h src/levels.h
+obj/0/x_centre.o: src/things.h src/s_centre.h src/objid.h src/t_centre.h
+dobj/0/x_centre.o: src/things.h src/s_centre.h src/objid.h src/t_centre.h
+obj/0/x_centre.o: src/v_centre.h src/x_centre.h
+dobj/0/x_centre.o: src/v_centre.h src/x_centre.h
+obj/0/x_exchng.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+dobj/0/x_exchng.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+obj/0/x_exchng.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+dobj/0/x_exchng.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+obj/0/x_exchng.o: src/wstructs.h src/input.h src/levels.h src/things.h
+dobj/0/x_exchng.o: src/wstructs.h src/input.h src/levels.h src/things.h
+obj/0/x_exchng.o: src/selectn.h src/objid.h src/x_exchng.h
+dobj/0/x_exchng.o: src/selectn.h src/objid.h src/x_exchng.h
+obj/0/x_hover.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+dobj/0/x_hover.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+obj/0/x_hover.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+dobj/0/x_hover.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+obj/0/x_hover.o: src/wstructs.h src/input.h src/drawmap.h src/_edit.h
+dobj/0/x_hover.o: src/wstructs.h src/input.h src/drawmap.h src/_edit.h
+obj/0/x_hover.o: src/objid.h src/levels.h src/things.h src/x_hover.h
+dobj/0/x_hover.o: src/objid.h src/levels.h src/things.h src/x_hover.h
+obj/0/x_mirror.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+dobj/0/x_mirror.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+obj/0/x_mirror.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+dobj/0/x_mirror.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+obj/0/x_mirror.o: src/wstructs.h src/input.h src/l_vertices.h src/selectn.h
+dobj/0/x_mirror.o: src/wstructs.h src/input.h src/l_vertices.h src/selectn.h
+obj/0/x_mirror.o: src/levels.h src/things.h src/objid.h src/s_vertices.h
+dobj/0/x_mirror.o: src/levels.h src/things.h src/objid.h src/s_vertices.h
+obj/0/x_mirror.o: src/t_centre.h src/v_centre.h src/x_mirror.h
+dobj/0/x_mirror.o: src/t_centre.h src/v_centre.h src/x_mirror.h
+obj/0/x_rotate.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+dobj/0/x_rotate.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+obj/0/x_rotate.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+dobj/0/x_rotate.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h
+obj/0/x_rotate.o: src/wstructs.h src/input.h src/l_vertices.h src/selectn.h
+dobj/0/x_rotate.o: src/wstructs.h src/input.h src/l_vertices.h src/selectn.h
+obj/0/x_rotate.o: src/levels.h src/things.h src/objid.h src/s_vertices.h
+dobj/0/x_rotate.o: src/levels.h src/things.h src/objid.h src/s_vertices.h
+obj/0/x_rotate.o: src/t_centre.h src/v_centre.h src/x_rotate.h
+dobj/0/x_rotate.o: src/t_centre.h src/v_centre.h src/x_rotate.h
+obj/0/x11.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h src/yerror.h
+dobj/0/x11.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h src/yerror.h
+obj/0/x11.o: src/ymemory.h src/aym.h src/windim.h src/wstructs.h src/input.h
+dobj/0/x11.o: src/ymemory.h src/aym.h src/windim.h src/wstructs.h src/input.h
+obj/0/x11.o: src/gfx.h src/x11.h
+dobj/0/x11.o: src/gfx.h src/x11.h
+obj/0/xref.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+dobj/0/xref.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+obj/0/xref.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h src/wstructs.h
+dobj/0/xref.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h src/wstructs.h
+obj/0/xref.o: src/input.h src/levels.h src/things.h src/selectn.h
+dobj/0/xref.o: src/input.h src/levels.h src/things.h src/selectn.h
+obj/0/yadex.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+dobj/0/yadex.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+obj/0/yadex.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h src/wstructs.h
+dobj/0/yadex.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h src/wstructs.h
+obj/0/yadex.o: src/input.h src/acolours.h src/colour.h src/bench.h
+dobj/0/yadex.o: src/input.h src/acolours.h src/colour.h src/bench.h
+obj/0/yadex.o: src/cfgfile.h src/disppic.h src/lists.h src/img.h src/editlev.h
+dobj/0/yadex.o: src/cfgfile.h src/disppic.h src/lists.h src/img.h src/editlev.h
+obj/0/yadex.o: src/endian.h src/flats.h src/game.h src/rgb.h src/gfx.h
+dobj/0/yadex.o: src/endian.h src/flats.h src/game.h src/rgb.h src/gfx.h
+obj/0/yadex.o: src/gfx2.h src/help1.h src/levels.h src/things.h src/mkpalette.h
+dobj/0/yadex.o: src/gfx2.h src/help1.h src/levels.h src/things.h src/mkpalette.h
+obj/0/yadex.o: src/palview.h src/patchdir.h src/sanity.h src/textures.h
+dobj/0/yadex.o: src/palview.h src/patchdir.h src/sanity.h src/textures.h
+obj/0/yadex.o: src/x11.h src/wadfile.h src/wadlist.h src/wadname.h src/wadres.h
+dobj/0/yadex.o: src/x11.h src/wadfile.h src/wadlist.h src/wadname.h src/wadres.h
+obj/0/yadex.o: src/spritdir.h src/lumpdir.h src/wads2.h
+dobj/0/yadex.o: src/spritdir.h src/lumpdir.h src/wads2.h
+obj/0/ytime.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+dobj/0/ytime.o: src/yadex.h src/config.h atclib/atclib.h src/bitvec.h
+obj/0/ytime.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h src/wstructs.h
+dobj/0/ytime.o: src/yerror.h src/ymemory.h src/aym.h src/windim.h src/wstructs.h
+obj/0/ytime.o: src/input.h src/ytime.h
+dobj/0/ytime.o: src/input.h src/ytime.h
+obj/0/_edit.o: src/objid.h
+dobj/0/_edit.o: src/objid.h
+obj/0/acolours.o: src/colour.h
+dobj/0/acolours.o: src/colour.h
+obj/0/bitvec.o: src/yerror.h src/ymemory.h
+dobj/0/bitvec.o: src/yerror.h src/ymemory.h
+obj/0/disppic.o: src/lists.h src/img.h
+dobj/0/disppic.o: src/lists.h src/img.h
+obj/0/drawmap.o: src/_edit.h src/objid.h
+dobj/0/drawmap.o: src/_edit.h src/objid.h
+obj/0/flats.o: src/lists.h src/img.h
+dobj/0/flats.o: src/lists.h src/img.h
+obj/0/game.o: src/rgb.h
+dobj/0/game.o: src/rgb.h
+obj/0/gamesky.o: src/wadname.h src/wstructs.h
+dobj/0/gamesky.o: src/wadname.h src/wstructs.h
+obj/0/gcolour1.o: src/colour.h
+dobj/0/gcolour1.o: src/colour.h
+obj/0/gcolour2.o: src/colour.h
+dobj/0/gcolour2.o: src/colour.h
+obj/0/gcolour3.o: src/colour.h
+dobj/0/gcolour3.o: src/colour.h
+obj/0/gfx3.o: src/rgbbmp.h
+dobj/0/gfx3.o: src/rgbbmp.h
+obj/0/highlt.o: src/edwidget.h src/objid.h
+dobj/0/highlt.o: src/edwidget.h src/objid.h
+obj/0/infobar.o: src/edwidget.h
+dobj/0/infobar.o: src/edwidget.h
+obj/0/l_super.o: src/levels.h src/wstructs.h src/things.h src/objid.h
+dobj/0/l_super.o: src/levels.h src/wstructs.h src/things.h src/objid.h
+obj/0/l_vertices.o: src/selectn.h
+dobj/0/l_vertices.o: src/selectn.h
+obj/0/levels.o: src/wstructs.h src/things.h
+dobj/0/levels.o: src/wstructs.h src/things.h
+obj/0/lists.o: src/img.h
+dobj/0/lists.o: src/img.h
+obj/0/menu.o: src/edwidget.h
+dobj/0/menu.o: src/edwidget.h
+obj/0/menubar.o: src/edwidget.h
+dobj/0/menubar.o: src/edwidget.h
+obj/0/modpopup.o: src/edwidget.h src/menu.h
+dobj/0/modpopup.o: src/edwidget.h src/menu.h
+obj/0/objects.o: src/objid.h
+dobj/0/objects.o: src/objid.h
+obj/0/objinfo.o: src/edwidget.h
+dobj/0/objinfo.o: src/edwidget.h
+obj/0/pic2img.o: src/img.h
+dobj/0/pic2img.o: src/img.h
+obj/0/s_centre.o: src/objid.h
+dobj/0/s_centre.o: src/objid.h
+obj/0/s_vertices.o: src/selectn.h
+dobj/0/s_vertices.o: src/selectn.h
+obj/0/selbox.o: src/edwidget.h
+dobj/0/selbox.o: src/edwidget.h
+obj/0/spot.o: src/edwidget.h src/gfx.h
+dobj/0/spot.o: src/edwidget.h src/gfx.h
+obj/0/spritdir.o: src/lumpdir.h
+dobj/0/spritdir.o: src/lumpdir.h
+obj/0/textures.o: src/lists.h src/img.h
+dobj/0/textures.o: src/lists.h src/img.h
+obj/0/things.o: src/wstructs.h
+dobj/0/things.o: src/wstructs.h
+obj/0/wadname.o: src/wstructs.h
+dobj/0/wadname.o: src/wstructs.h
+obj/0/wadres.o: src/spritdir.h src/lumpdir.h
+dobj/0/wadres.o: src/spritdir.h src/lumpdir.h
+obj/0/yadex.o: src/config.h atclib/atclib.h src/bitvec.h src/yerror.h
+dobj/0/yadex.o: src/config.h atclib/atclib.h src/bitvec.h src/yerror.h
+obj/0/yadex.o: src/ymemory.h src/aym.h src/windim.h src/wstructs.h src/input.h
+dobj/0/yadex.o: src/ymemory.h src/aym.h src/windim.h src/wstructs.h src/input.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ygd/doom.ygd	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,513 @@
+# Yadex game definition file version 4
+#
+#	doom.ygd
+#	Yadex Game Definitions for Doom and Ultimate Doom
+#	See doc/ygd.html for the specs.
+#	AYM 1998-01-29
+#
+
+# EDGE stuff courtesy of Andrew Apted. Mistakes courtesy of AYM.
+# Boom stuff courtesy of Andrew Apted, 2000-09-20.
+
+level_format    doom
+level_name      e1m1
+picture_format  normal
+sky_flat        f_sky1
+texture_format  normal
+texture_lumps   normal
+
+#
+#	Definition of linedef type groups
+#	Format is : ldtgroup <ldtgroup> <description>
+#
+
+ldtgroup d "Door"
+ldtgroup r "Door (red key)"
+ldtgroup y "Door (yellow key)"
+ldtgroup b "Door (blue key)"
+ldtgroup D "Door (turbo)"
+ldtgroup l "Lift"
+ldtgroup v "Elevator"
+ldtgroup F "Floor (raise)"
+ldtgroup f "Floor (lower)"
+ldtgroup c "Ceiling"
+ldtgroup C "Crushing ceiling"
+ldtgroup t "Teleport"
+ldtgroup L "Light"
+ldtgroup e "End level"
+ldtgroup m "Moving floor"
+ldtgroup s "Raising stairs"
+ldtgroup A "Animated"
+ldtgroup E "Extrafloor"
+ldtgroup x "Misc."
+
+#
+#	Definition of linedef types
+#	Format is : ldt <number> <ldtgroup> <shortdesc> <longdesc>
+#	<shortdesc> must not exceed 16 characters.
+#
+
+ldt   0 x "-- Normal"        "--  Normal"
+ldt   1 d "DR Open door"     "DR  Open  door"
+ldt   2 d "W1 Open door (O)" "W1  Open  door (stays open)"
+ldt   3 d "W1 Close door"    "W1  Close door"
+ldt   4 d "W1 Open door"     "W1  Open  door"
+ldt   5 F "W1 Floor up LIC"  "W1  Raise floor to LIC"
+ldt   6 C "W1 Crush FF"      "W1  Start fast crushing, fast hurt"
+ldt   7 s "S1 Raise stairs"  "S1  Raise stairs (several sectors 0/999)"
+ldt   8 s "W1 Raise stairs"  "W1  Raise stairs (several sectors 0/999)"
+ldt   9 x "S1 Donut"         "S1  Lower floor, raise Ne. floor (NXP) 'Donut'"
+ldt  10 l "W1 Lower lift"    "W1  Lower lift"
+ldt  11 e "S- End level"     "S-  End level, go to next level"
+ldt  12 L "W1 Light to HE"   "W1  Light level goes to HE"
+ldt  13 L "W1 Light to 255"  "W1  Light level goes to 255"
+ldt  14 F "S1& F. up 32 TX"  "S1& Raise floor by 32 (TX)"
+ldt  15 F "S1& F. up 24 TX"  "S1& Raise floor by 24 (TX)"
+ldt  16 d "W1 Close for 30s" "W1  Close door for 30 seconds"
+ldt  17 L "W1 Start blink"   "W1  Start blinking lights"
+ldt  18 F "S1 Floor up nhEF" "S1  Raise floor to nhEF"
+ldt  19 f "W1 Floor dn HEF"  "W1  Lower floor to HEF"
+ldt  20 F "S1& F up nhEF TX" "S1& Raise floor to nhEF (TX)"
+ldt  21 l "S1 Lower lift"    "S1  Lower lift"
+ldt  22 F "W1& F up nhEF TX" "W1& Raise floor to nhEF (TX)"
+ldt  23 f "S1 Floor dn LEF"  "S1  Lower floor to LEF"
+ldt  24 F "G1 Floor up LIC"  "G1  Raise floor to LIC"
+ldt  25 C "W1 Crush FS"      "W1  Start fast crushing, slow hurt"
+ldt  26 b "DR Open blue dr"  "DR  Open  door, blue key"
+ldt  27 y "DR Open yel dr"   "DR  Open  door, yellow key"
+ldt  28 r "DR Open red dr"   "DR  Open  door, red key"
+ldt  29 d "S1 Open door"     "S1  Open  door"
+ldt  30 F "W1 Floor up SLT"  "W1  Raise floor by ShortestLowerTexture"
+ldt  31 d "D1 Open door (O)" "D1  Open  door (stays open)"
+ldt  32 b "D1 Open blu (O)"  "D1  Open  door (stays open), blue key"
+ldt  33 r "D1 Open red (O)"  "D1  Open  door (stays open), red key"
+ldt  34 y "D1 Open yel (O)"  "D1  Open  door (stays open), yellow key"
+ldt  35 L "W1 Light to 35"   "W1  Light level goes to 35"
+ldt  36 f "W1 F. DN HEF+8"   "W1  Lower turbo floor to HEF + 8"
+ldt  37 f "W1 F. dn LEF NXP" "W1  Lower floor to LEF (NXP)"
+ldt  38 f "W1 Floor dn LEF"  "W1  Lower floor to LEF"
+ldt  39 t "W1 Teleport"      "W1  Teleport to another sector"
+ldt  40 c "W1 Ceil up HEC"   "W1  Raise ceiling to HEC"
+ldt  41 c "S1 Ceil dn floor" "S1  Lower ceiling to floor"
+ldt  42 d "SR Close door"    "SR  Close door"
+ldt  43 c "SR Ceil dn floor" "SR  Lower ceiling to floor"
+ldt  44 c "W1 Ceil dn flr+8" "W1  Lower ceiling to floor + 8"
+ldt  45 f "SR Floor dn HEF"  "SR  Lower floor to HEF"
+ldt  46 d "GR Open door (O)" "GR  Open  door (stays open)"
+ldt  47 F "G1 F. up nhEF TX" "G1  Raise floor to nhEF (TX)"
+ldt  48 A "-- Scroll left"   "--  Scrolling wall, left"
+ldt  49 c "S1 Ceil dn flr+8" "S1  Lower ceiling to floor + 8"
+ldt  50 d "S1 Close door"    "S1  Close door"
+ldt  51 e "S- Secret level"  "S-  End level, go to secret level"
+ldt  52 e "W- End level"     "W-  End level, go to next level"
+ldt  53 m "W1 Start moving"  "W1  Start moving floor"
+ldt  54 m "W1 Stop moving f" "W1  Stop  moving floor"
+ldt  55 F "S1 F. up LIC-8"   "S1  Raise floor to LIC - 8, crush"
+ldt  56 F "W1& F. up LIC-8"  "W1& Raise floor to LIC - 8, crush"
+ldt  57 C "W1& Stop crush"   "W1& Stop  crushing"
+ldt  58 F "W1 Floor up 24"   "W1  Raise floor by 24"
+ldt  59 F "W1 F. up 24 TXP"  "W1  Raise floor by 24 (TXP)"
+ldt  60 f "SR Floor dn LEF"  "SR  Lower floor to LEF"
+ldt  61 d "SR Open door (O)" "SR  Open  door (stays open)"
+ldt  62 l "SR Lower lift"    "SR  Lower lift"
+ldt  63 d "SR Open door"     "SR  Open  door"
+ldt  64 F "SR Floor up LIC"  "SR  Raise floor to LIC"
+ldt  65 F "SR F. up LIC-8"   "SR  Raise floor to LIC - 8, crush"
+ldt  66 F "SR& F. up 24 TX"  "SR& Raise floor by 24 (TX)"
+ldt  67 F "SR& F. up 32 TX"  "SR& Raise floor by 32 (TX)"
+ldt  68 f "SR& F up nhEF TX" "SR& Raise floor to nhEF (TX)"
+ldt  69 F "SR F. up nhEF"    "SR  Raise floor to nhEF"
+ldt  70 f "SR F. DN HEF+8"   "SR  Lower turbo floor to HEF + 8"
+ldt  71 f "S1 F. DN HEF+8"   "S1  Lower turbo floor to HEF + 8"
+ldt  72 c "WR Ceil dn flr+8" "WR  Lower ceiling to floor + 8"
+ldt  73 C "WR& Crush SS"     "WR& Start slow crushing, slow hurt"
+ldt  74 C "WR& Stop crush"   "WR& Stop  crushing"
+ldt  75 d "WR Close door"    "WR  Close door"
+ldt  76 d "WR Close for 30s" "WR  Close door for 30 seconds"
+ldt  77 C "WR& Crush FF"     "WR& Start fast crushing, fast hurt"
+
+ldt  78 x "SR Floor -- NXP"  "SR  Floor transfer (NXP) [Boom]"
+
+ldt  79 L "WR Light to 35"   "WR  Light level goes to 35"
+ldt  80 L "WR Light to HE"   "WR  Light level goes to HE"
+ldt  81 L "WR Light to 255"  "WR  Light level goes to 255"
+ldt  82 f "WR Floor dn LEF"  "WR  Lower floor to LEF"
+ldt  83 f "WR Floor dn HEF"  "WR  Lower floor to HEF"
+ldt  84 f "WR F. dn LEF NXP" "WR  Lower floor to LEF (NXP)"
+
+ldt  85 A "-- Scroll right"  "--  Scrolling wall, right [Boom]"
+
+ldt  86 d "WR Open door (O)" "WR  Open  door (stays open)"
+ldt  87 m "WR& Start moving" "WR& Start moving floor"
+ldt  88 l "WR Lower lift"    "WR  Lower lift"
+ldt  89 m "WR& Stop moving"  "WR& Stop  moving floor"
+ldt  90 d "WR Open door"     "WR  Open  door"
+ldt  91 F "WR Floor up LIC"  "WR  Raise floor to LIC"
+ldt  92 F "WR Floor up 24"   "WR  Raise floor by 24"
+ldt  93 F "WR F. up 24 TXP"  "WR  Raise floor by 24 (TXP)"
+ldt  94 F "WR F. up LIC-8"   "WR  Raise floor to LIC - 8, crush"
+ldt  95 F "WR F. up nhEF TX" "WR  Raise floor to nhEF (TX)"
+ldt  96 F "WR Floor up SLT"  "WR  Raise floor by ShortestLowerTexture"
+ldt  97 t "WR Teleport"      "WR  Teleport to another sector"
+ldt  98 f "WR F. DN HEF+8"   "WR  Lower turbo floor to HEF + 8"
+ldt  99 b "SR OPEN blu door" "SR  Open  turbo door, blue key [v1.6]"
+ldt 100 s "W1 RaiseStairs16" "W1  Raise stairs (step=16), crush [v1.6]"
+ldt 101 F "S1 Floor up LIC"  "S1  Raise floor to LIC"
+ldt 102 f "S1 Floor dn HEF"  "S1  Lower floor to HEF"
+ldt 103 d "S1 Open door (O)" "S1  Open  door (stays open)"
+ldt 104 L "W1 Light to LE"   "W1  Light level goes to LE"
+ldt 105 D "WR OPEN door"     "WR  Open  turbo door [v1.6]"
+ldt 106 D "WR OPEN door (O)" "WR  Open  turbo door (stays open) [v1.6]"
+ldt 107 D "WR CLOSE door"    "WR  Close turbo door [v1.6]"
+ldt 108 D "W1 OPEN door"     "W1  Open  turbo door [v1.6]"
+ldt 109 D "W1 OPEN door (O)" "W1  Open  turbo door (stays open) [v1.6]"
+ldt 110 D "W1 CLOSE door"    "W1  Close turbo door [v1.6]"
+ldt 111 D "S1 OPEN door"     "S1  Open  turbo door [v1.6]"
+ldt 112 D "S1 OPEN door (O)" "S1  Open  turbo door (stays open) [v1.6]"
+ldt 113 D "S1 CLOSE door"    "S1  Close turbo door [v1.6]"
+ldt 114 D "SR OPEN door"     "SR  Open  turbo door [v1.6]"
+ldt 115 D "SR OPEN door (O)" "SR  Open  turbo door (stays open) [v1.6]"
+ldt 116 D "SR CLOSE door"    "SR  Close turbo door [v1.6]"
+ldt 117 D "DR OPEN door"     "DR  Open  turbo door [v1.6]"
+ldt 118 D "D1 OPEN door (O)" "D1  Open  turbo door (stays open) [v1.6]"
+ldt 119 F "W1 Floor up nhEF" "W1  Raise floor to nhEF [v1.6]"
+ldt 120 l "WR LOWER lift"    "WR  Lower turbo lift [v1.6]"
+ldt 121 l "W1 LOWER lift"    "W1  Lower turbo lift [v1.6]"
+ldt 122 l "S1 LOWER lift"    "S1  Lower turbo lift [v1.6]"
+ldt 123 l "SR LOWER lift"    "SR  Lower turbo lift [v1.6]"
+ldt 124 e "W- Secret level"  "W-  End level, go to secret level [v1.6]"
+ldt 125 t "W1 Teleport mons" "W1  Teleport monsters only [v1.6]"
+ldt 126 t "WR Teleport mons" "WR  Teleport monsters only [v1.6]"
+ldt 127 s "S1 RaiseStairs16" "S1  Raise stairs (step=16), crush [v1.6]"
+ldt 128 F "WR Floor up nhEF" "WR  Raise floor to nhEF [v1.6]"
+ldt 129 F "WR Floor UP nhEF" "WR  Raise turbo floor to nhEF [v1.6]"
+ldt 130 F "W1 Floor UP nhEF" "W1  Raise turbo floor to nhEF [v1.6]"
+ldt 131 F "S1 Floor UP nhEF" "S1  Raise turbo floor to nhEF [v1.6]"
+ldt 132 F "SR Floor UP nhEF" "SR  Raise turbo floor to nhEF [v1.6]"
+ldt 133 b "S1 OPEN blu door" "S1  Open  turbo door, blue key [v1.6]"
+ldt 134 r "SR OPEN red door" "SR  Open  turbo door, red key [v1.6]"
+ldt 135 r "S1 OPEN red door" "S1  Open  turbo door, red key [v1.6]"
+ldt 136 y "SR OPEN yel door" "SR  Open  turbo door, yellow key [v1.6]"
+ldt 137 y "S1 OPEN yel door" "S1  Open  turbo door, yellow key [v1.6]"
+ldt 138 L "SR Light to 255"  "SR  Light level goes to 255 [v1.6]"
+ldt 139 L "SR Light to 0"    "SR  Light level goes to 0 [v1.6]"
+ldt 140 F "S1 Floor up 512"  "S1  Raise floor by 512, medium speed [v1.6]"
+ldt 141 C "W1& Crush SS sil" "W1& Start slow crushing, slow hurt, silent [v1.6]"
+
+ldt 142 F "W1 Floor up 512"  "W1  Raise floor by 512 [Boom]"
+ldt 143 l "W1& F. up 24 TX"  "W1& Raise floor by 24 (TX) [Boom]"
+ldt 144 l "W1& F. up 32 TX"  "W1& Raise floor by 32 (TX) [Boom]"
+ldt 145 c "W1 Ceil dn floor" "W1  Lower ceiling to floor [Boom]"
+ldt 146 x "W1 Donut"         "W1  Lower floor, raise NE floor (NXP) [Boom]"
+ldt 147 F "WR Floor up 512"  "WR  Raise floor by 512 [Boom]"
+ldt 148 l "WR& F. up 24 TX"  "WR& Raise floor by 24 (TX) [Boom]"
+ldt 149 l "WR& F. up 32 TX"  "WR& Raise floor by 32 (TX) [Boom]"
+ldt 150 C "WR& Crush SS sil" "WR& Start slow crushing, silent [Boom]"
+ldt 151 c "WR Ceil up HEC"   "WR  Raise ceiling to HEC [Boom]"
+ldt 152 c "WR Ceil dn floor" "WR  Lower ceiling to floor [Boom]"
+ldt 153 x "W1 Floor -- TXP"  "W1  Floor transfer (TXP) [Boom]"
+ldt 154 x "WR Floor -- TXP"  "WR  Floor transfer (TXP) [Boom]"
+ldt 155 x "WR Donut"         "WR  Lower floor, raise NE floor (NXP) [Boom]"
+ldt 156 L "WR Start blink"   "WR  Start blinking lights [Boom]"
+ldt 157 L "WR Light to LE"   "WR  Light level goes to LE [Boom]"
+ldt 158 F "S1 Floor up SLT"  "S1  Raise floor by ShortestLowerTex [Boom]"
+ldt 159 f "S1 F. dn LEF NX"  "S1  Lower floor to LEF (NXP) [Boom]"
+ldt 160 F "S1 F. up 24 TXP"  "S1  Raise floor by 24 (TXP) [Boom]"
+ldt 161 F "S1 Floor up 24"   "S1  Raise floor by 24 [Boom]"
+ldt 162 m "S1 Start moving"  "S1  Start moving floor [Boom]"
+ldt 163 m "S1 Stop moving f" "S1  Stop  moving floor [Boom]"
+ldt 164 C "S1 Crush FF"      "S1  Start fast crushing [Boom]"
+ldt 165 C "S1& Crush SS sil" "S1& Start slow crushing, silent [Boom]"
+ldt 166 c "S1 Ceil up HEC"   "S1  Raise ceiling to HEC [Boom]"
+ldt 167 c "S1 Ceil dn flr+8" "S1  Lower ceiling to floor + 8 [Boom]"
+ldt 168 C "S1& Stop crush"   "S1& Stop  crushing [Boom]"
+ldt 169 L "S1 Light to HE"   "S1  Light level goes to HE [Boom]"
+ldt 170 L "S1 Light to 0"    "S1  Light level goes to 0 [Boom]"
+ldt 171 L "S1 Light to 255"  "S1  Light level goes to 255 [Boom]"
+ldt 172 L "S1 Start blink"   "S1  Start blinking lights [Boom]"
+ldt 173 L "S1 Light to LE"   "S1  Light level goes to LE [Boom]"
+ldt 174 t "S1 Teleport"      "S1  Teleport to another sector [Boom]"
+ldt 175 d "S1 Close for 30s" "S1  Close door for 30 seconds [Boom]"
+ldt 176 F "SR Floor up SLT"  "SR  Raise floor by ShortestLowerTex [Boom]"
+ldt 177 f "SR F. dn LEF NX"  "SR  Lower floor to LEF (NXP) [Boom]"
+ldt 178 F "SR Floor up 512"  "SR  Raise floor by 512 [Boom]"
+ldt 179 F "SR F. up 24 TXP"  "SR  Raise floor by 24 (TXP) [Boom]"
+ldt 180 F "SR Floor up 24"   "SR  Raise floor by 24 [Boom]"
+ldt 181 m "SR Start moving"  "SR  Start moving floor [Boom]"
+ldt 182 m "SR Stop moving f" "SR  Stop  moving floor [Boom]"
+ldt 183 C "SR Crush FF"      "SR  Start fast crushing [Boom]"
+ldt 184 C "SR& Crush SS"     "SR& Start slow crushing [Boom]"
+ldt 185 C "SR& Crush SS sil" "SR& Start slow crushing, silent [Boom]"
+ldt 186 c "SR Ceil up HEC"   "SR  Raise ceiling to HEC [Boom]"
+ldt 187 c "SR Ceil dn flr+8" "SR  Lower ceiling to floor + 8 [Boom]"
+ldt 188 C "SR& Stop crush"   "SR& Stop  crushing [Boom]"
+ldt 189 x "S1 Floor -- TXP"  "S1  Floor transfer (TXP) [Boom]"
+ldt 190 x "SR Floor -- TXP"  "SR  Floor transfer (TXP) [Boom]"
+ldt 191 x "SR Donut"         "SR  Lower floor, raise NE floor (NXP) [Boom]"
+ldt 192 L "SR Light to HE"   "SR  Light level goes to HE [Boom]"
+ldt 193 L "SR Start blink"   "SR  Start blinking lights [Boom]"
+ldt 194 L "SR Light to LE"   "SR  Light level goes to LE [Boom]"
+ldt 195 t "SR Teleport"      "SR  Teleport to another sector [Boom]"
+ldt 196 d "SR Close for 30s" "SR  Close door for 30 seconds [Boom]"
+ldt 197 e "G- End level"     "G-  End level, go to next level [Boom]"
+ldt 198 e "G- End level"     "G-  End level, go to secret level [Boom]"
+ldt 199 c "W1 Ceil dn LEC"   "W1  Lower ceiling to LEC [Boom]"
+ldt 200 c "W1 Ceil dn HEF"   "W1  Lower ceiling to HEF [Boom]"
+ldt 201 c "WR Ceil dn LEC"   "WR  Lower ceiling to LEC [Boom]"
+ldt 202 c "WR Ceil dn HEF"   "WR  Lower ceiling to HEF [Boom]"
+ldt 203 c "S1 Ceil dn LEC"   "S1  Lower ceiling to LEC [Boom]"
+ldt 204 c "S1 Ceil dn HEF"   "S1  Lower ceiling to HEF [Boom]"
+ldt 205 c "SR Ceil dn LEC"   "SR  Lower ceiling to LEC [Boom]"
+ldt 206 c "SR Ceil dn HEF"   "SR  Lower ceiling to HEF [Boom]"
+ldt 207 t "W1 Teleport pres" "W1  Teleport preserving dir [Boom]"
+ldt 208 t "WR Teleport pres" "WR  Teleport preserving dir [Boom]"
+ldt 209 t "S1 Teleport pres" "S1  Teleport preserving dir [Boom]"
+ldt 210 t "SR Teleport pres" "SR  Teleport preserving dir [Boom]"
+ldt 211 m "SR Floor toggle"  "SR  Floor toggle to ceil [Boom]"
+ldt 212 m "WR Floor toggle"  "WR  Floor toggle to ceil [Boom]"
+ldt 213 L "-- Xfer F. light" "--  Transfer floor lighting [Boom]"
+ldt 214 A "-- Scrl C. accel" "--  Scroll ceiling with accel [Boom]"
+ldt 215 A "-- Scrl F. accel" "--  Scroll floor with accel [Boom]"
+ldt 216 A "-- Push F. accel" "--  Push objects with accel [Boom]"
+ldt 217 A "-- Sc/Pu F. accl" "--  Scroll & push with accel [Boom]"
+ldt 218 A "-- Scrl wall acc" "--  Scroll wall with accel [Boom]"
+ldt 219 f "W1 F. dn nlEF"    "W1  Lower floor to nlEF [Boom]"
+ldt 220 f "WR F. dn nlEF"    "WR  Lower floor to nlEF [Boom]"
+ldt 221 f "S1 F. dn nlEF"    "S1  Lower floor to nlEF [Boom]"
+ldt 222 f "SR F. dn nlEF"    "SR  Lower floor to nlEF [Boom]"
+ldt 223 x "-- Friction"      "--  Set friction in tagged sectors [Boom]"
+ldt 224 x "-- Wind force"    "--  Set wind in tagged sectors [Boom]"
+ldt 225 x "-- Current force" "--  Set current in tagged sectors [Boom]"
+ldt 226 x "-- Point force"   "--  Set point force in sectors [Boom]"
+ldt 227 v "W1 Elevator nhEF" "W1  Raise elevator to nhEF [Boom]"
+ldt 228 v "WR Elevator nhEF" "WR  Raise elevator to nhEF [Boom]"
+ldt 229 v "S1 Elevator nhEF" "S1  Raise elevator to nhEF [Boom]"
+ldt 230 v "SR Elevator nhEF" "SR  Raise elevator to nhEF [Boom]"
+ldt 231 v "W1 Elevator nlEF" "W1  Lower elevator to nlEF [Boom]"
+ldt 232 v "WR Elevator nlEF" "WR  Lower elevator to nlEF [Boom]"
+ldt 233 v "S1 Elevator nlEF" "S1  Lower elevator to nlEF [Boom]"
+ldt 234 v "SR Elevator nlEF" "SR  Lower elevator to nlEF [Boom]"
+ldt 235 v "W1 Elevator curr" "W1  Move elevator to Current [Boom]"
+ldt 236 v "WR Elevator curr" "WR  Move elevator to Current [Boom]"
+ldt 237 v "S1 Elevator curr" "S1  Move elevator to Current [Boom]"
+ldt 238 v "SR Elevator curr" "SR  Move elevator to Current [Boom]"
+ldt 239 x "W1 Floor -- NXP"  "W1  Floor transfer (NXP) [Boom]"
+ldt 240 x "WR Floor -- NXP"  "WR  Floor transfer (NXP) [Boom]"
+ldt 241 x "S1 Floor -- NXP"  "S1  Floor transfer (NXP) [Boom]"
+ldt 242 x "-- Deep water"    "--  Deep water effect [Boom]"
+ldt 243 t "W1 Telept line"   "W1  Teleport to tagged line [Boom]"
+ldt 244 t "WR Telept line"   "WR  Teleport to tagged line [Boom]"
+ldt 245 A "-- Scrl C. disp"  "--  Scroll ceiling by displacement [Boom]"
+ldt 246 A "-- Scrl F. disp"  "--  Scroll floor by displacement [Boom]"
+ldt 247 A "-- Push F. disp"  "--  Push objects by displacement [Boom]"
+ldt 248 A "-- Sc/Pu F. disp" "--  Scroll & push by displacement [Boom]"
+ldt 249 A "-- Scrl wall dis" "--  Scroll wall by displacement [Boom]"
+ldt 250 A "-- Scroll ceil"   "--  Scroll tagged ceiling [Boom]"
+ldt 251 A "-- Scroll floor"  "--  Scroll tagged floor [Boom]"
+ldt 252 A "-- Push on floor" "--  Push objects on tagged floor [Boom]"
+ldt 253 A "-- Scroll,push f" "--  Scroll & push tagged floor [Boom]"
+ldt 254 A "-- Scrl wal with" "--  Scroll tagged wall with F/C [Boom]"
+ldt 255 A "-- Scrl wal side" "--  Scroll wall using sidedef [Boom]"
+ldt 256 s "WR Raise stairs"  "WR  Raise stairs (several sectors) [Boom]"
+ldt 257 s "WR RaiseStairs16" "WR  Raise stairs (step=16), crush [Boom]"
+ldt 258 s "SR Raise stairs"  "SR  Raise stairs (several sectors) [Boom]"
+ldt 259 s "SR RaiseStairs16" "SR  Raise stairs (step=16), crush [Boom]"
+ldt 260 A "-- Translucency"  "--  Make tagged lines translucent [Boom]"
+ldt 261 L "-- Xfer C. light" "--  Transfer ceiling lighting [Boom]"
+ldt 262 t "W1 Telept line R" "W1  Teleport to line, reverse [Boom]"
+ldt 263 t "WR Telept line R" "WR  Teleport to line, reverse [Boom]"
+ldt 264 t "W1 Tpt line mons" "W1  Teleport monsters to line [Boom]"
+ldt 265 t "WR Tpt line mons" "WR  Teleport monsters to line [Boom]"
+ldt 266 t "W1 Tpt L. mons R" "W1  Teleport monsters to line, rev [Boom]"
+ldt 267 t "WR Tpt L. mons R" "WR  Teleport monsters to line, rev [Boom]"
+ldt 268 t "W1 Teleport mons" "W1  Teleport monsters only [Boom]"
+ldt 269 t "WR Teleport mons" "WR  Teleport monsters only [Boom]"
+
+ldt 271 x "-- Xfer sky"      "--  Xfer straight upper to sky tex. [MBF]"
+ldt 272 x "-- Xfer mir. sky" "--  Xfer mirrored upper to sky tex. [MBF]"
+
+ldt 400 E "-- Thick EF"      "--  Thick extrafloor [EDGE]"
+ldt 401 E "-- Thick EF upr"  "--  Thick extrafloor, side upper [EDGE]"
+ldt 402 E "-- Thick EF lwr"  "--  Thick extrafloor, side lower [EDGE]"
+ldt 403 E "-- Liq EF opaque" "--  Liquid extrafloor, opaque [EDGE]"
+ldt 404 E "-- Liquid EF 20%" "--  Liquid extrafloor, 20% translucent [EDGE]"
+ldt 405 E "-- Liquid EF 40%" "--  Liquid extrafloor, 40% translucent [EDGE]"
+ldt 406 E "-- Liquid EF 60%" "--  Liquid extrafloor, 60% translucent [EDGE]"
+ldt 407 E "-- Liquid EF 80%" "--  Liquid extrafloor, 80% translucent [EDGE]"
+ldt 408 E "-- Liq EF invis"  "--  Liquid extrafloor, invisible [EDGE]"
+
+ldt 9000 A "-- Scroll right" "--  Scrolling wall, right [EDGE]"
+ldt 9001 A "-- Scroll up"    "--  Scrolling wall, up [EDGE]"
+ldt 9002 A "-- Scroll down"  "--  Scrolling wall, down [EDGE]"
+ldt 9003 A "-- Scroll L+U"   "--  Scrolling wall, left and up [EDGE]"
+ldt 9004 A "-- Scroll L+D"   "--  Scrolling wall, left and down [EDGE]"
+ldt 9005 A "-- Scroll R+U"   "--  Scrolling wall, right and up [EDGE]"
+ldt 9006 A "-- Scroll R+D"   "--  Scrolling wall, right and down [EDGE]"
+ldt 9097 t "WR Teleport prv" "WR  Teleport, preserving direction [EDGE]"
+
+#
+#	Definition of sector types
+#	Format is : st <number> <shortdesc> <longdesc>
+#	<shortdesc> must not exceed 14 characters.
+#
+
+st  0 "X Normal"       "X Normal"
+st  1 "  Blinks rand"  "  Light blinks randomly"
+st  2 "  Flashes 2 Hz" "  Light flashes 2 Hz"
+st  3 "  Flashes 1 Hz" "  Light flashes 1 Hz"
+st  4 "P -20% & 2Hz"   "P -10/20% health, flashes 2 Hz"
+st  5 "P -10% health"  "P -5/10% health"
+st  7 "P -5% health"   "P -2/5% health"
+st  8 "  Oscillates"   "  Light oscillates"
+st  9 "P Secret"       "P Secret"
+st 10 "  Closes 30 s"  "  30 s after level start, ceiling closes like a door"
+st 11 "P -20% & end"   "P -10/20% health and end level when health <= 10%"
+st 12 "  Flash1Hz syn" "  Light flashes 1 Hz, synchronized"
+st 13 "  Flash2Hz syn" "  Light flashes 2 Hz, synchronized"
+st 14 "  Opens 300 s"  "  300 s after level start, ceiling opens like a door"
+st 16 "P -20% health"  "P -10/20% health"
+st 17 "  Flicker rand" "  Light flickers on and off randomly [v1.6]"
+
+#
+#	Definition of thing groups
+#	Format is : thinggroup <thinggroup> <colour> <description>
+#
+
+thinggroup p rgb:4/f/4 "Player"
+thinggroup m rgb:f/0/0 "Monster"
+thinggroup w rgb:f/a/0 "Weapon"
+thinggroup a rgb:8/5/0 "Ammunition"
+thinggroup h rgb:2/8/0 "Health & armour"
+thinggroup b rgb:2/8/0 "Misc. bonus"
+thinggroup k rgb:f/0/f "Key"
+thinggroup d rgb:6/6/c "Misc. decoration"
+thinggroup l rgb:6/6/c "Light source"
+thinggroup g rgb:6/6/c "Gory decoration"
+thinggroup c rgb:6/6/c "Corpse"
+thinggroup s rgb:0/b/d "Special"
+
+#
+#	Definition of things
+#	Format is :
+#	thing <number> <thinggroup> <flags> <radius> <desc> [<sprite>]
+#	<desc> must not exceed 19 characters.
+#
+
+thing 2007 a -  20 "Clip"			CLIP
+thing 2048 a -  20 "Box of bullets"		AMMO
+thing 2008 a -  20 "4 shotgun shells"		SHEL
+thing 2049 a -  20 "Box shotgun shells"		SBOX
+thing 2010 a -  20 "Rocket"			ROCK
+thing 2046 a -  20 "Box of rockets"		BROK
+thing 2047 a -  20 "Energy cell"		CELL
+thing   17 a -  20 "Energy cell pack"		CELP
+thing    8 a -  20 "Backpack full ammo"		BPAK
+
+thing 2025 b -  20 "Rad. shielding suit"	SUIT
+thing 2026 b -  20 "Computer area map"		PMAP
+thing 2024 b -  20 "Partial invis."		PINS
+thing 2023 b -  20 "Berserk"			PSTR
+thing 2022 b -  20 "Invulnerability"		PINV
+thing 2045 b -  20 "Light amp. visor"		PVIS
+thing 7000 b -  20 "Night vision [EDGE]"	NVSC
+thing 2016 b -  16 "Evil sceptre [PR]"		BON3
+thing 2017 b -  16 "Unholy bible [PR]"		BON4
+
+thing   15 c -  16 "Dead player (green)"	PLAYN
+thing   18 c -  20 "Dead trooper"		POSSL
+thing   19 c -  20 "Dead sergeant"		SPOSL
+thing   20 c -  20 "Dead imp"			TROOM
+thing   21 c -  16 "Dead demon"			SARGN
+thing   22 c -  16 "Dead cacodemon"		HEADL
+thing   23 c -  16 "Dead lost soul"		SKULK
+
+thing 2035 d -  10 "Barrel"			BAR1
+thing 7011 d -  10 "Unstable barrel [EDGE]"	BEXP	# FIXME cut off
+thing   48 d -  16 "Technical column"		ELEC
+thing   30 d -  16 "Tall green pillar"		COL1
+thing   32 d -  16 "Tall red pillar"		COL3
+thing   31 d -  16 "Short green pillar"		COL2
+thing   33 d -  16 "Short red pillar"		COL4
+thing   36 d -  16 "Pillar w/heart"		COL5
+thing   37 d -  16 "Red pillar w/skull"		COL6
+thing   41 d -  16 "Evil eye"			CEYE
+thing   42 g -  16 "Floating skulls"		FSKU
+thing   47 d -  16 "Brown stub"			SMIT
+thing 7010 d -  16 "Grey stub [EDGE]"		SMT2
+thing   54 d -  32 "Brown tree"			TRE2
+thing   43 d -  16 "Grey tree"			TRE1
+
+thing   10 g -  16 "Mushed player"		PLAYW
+thing   12 g -  16 "Mushed player 2"		PLAYW
+thing   24 g -  16 "Pool of blood"		POL5
+thing   27 g -  16 "Pole with skull"		POL4
+thing   28 g -  16 "Skewer with heads"		POL2
+thing   29 g -  16 "Pile of skulls"		POL3
+thing   25 g -  16 "Impaled body"		POL1
+thing   26 g -  16 "Impaled twitching"		POL6
+thing   49 g -  16 "Swaying body O"		GOR1
+thing   63 g -  16 "Swaying body"		GOR1
+thing   50 g -  16 "Hanging arms out O"		GOR2
+thing   59 g -  16 "Hanging arms out"		GOR2
+thing   53 g -  16 "Hanging leg O"		GOR5
+thing   62 g -  16 "Hanging leg"		GOR5
+thing   51 g -  16 "Hanging one-legged O"	GOR3	# FIXME cut off
+thing   61 g -  16 "Hanging one-legged"		GOR3
+thing   52 g -  16 "Hanging torso O"		GOR4
+thing   60 g -  16 "Hanging torso"		GOR4
+
+thing 2014 h -  20 "Health bonus"		BON1
+thing 2011 h -  20 "Stimpack"			STIM
+thing 2012 h -  20 "Medikit"			MEDI
+thing 2013 h -  20 "Supercharge"		SOUL
+thing 2015 h -  20 "Armor bonus"		BON2
+thing 2018 h -  20 "Armor"			ARM1
+thing 2019 h -  20 "Megaarmor"			ARM2
+
+thing    5 k -  20 "Blue keycard"		BKEY
+thing    6 k -  20 "Yellow keycard"		YKEY
+thing   13 k -  20 "Red keycard"		RKEY
+thing   40 k -  20 "Blue skull key"		BSKU
+thing   39 k -  20 "Yellow skull key"		YSKU
+thing   38 k -  20 "Red skull key"		RSKU
+
+thing 2028 l -  16 "Lamp"			COLU
+thing   34 l -  16 "Candle"			CAND
+thing   35 l -  16 "Candelabra"			CBRA
+thing   44 l -  16 "Tall blue torch"		TBLU
+thing   45 l -  16 "Tall green torch"		TGRN
+thing   46 l -  16 "Tall red torch"		TRED
+thing   55 l -  16 "Short blue torch"		SMBT
+thing   56 l -  16 "Short green torch"		SMGT
+thing   57 l -  16 "Short red torch"		SMRT
+
+thing 3004 m -  20 "Trooper"			POSS
+thing    9 m -  20 "Sergeant"			SPOS
+thing 3001 m -  20 "Imp"			TROO
+thing 3002 m -  30 "Demon"			SARG
+thing 3003 m -  24 "Baron of hell"		BOSS
+thing   58 m s  30 "Spectre"			SARG
+thing 3006 m -  16 "Lost soul"			SKUL
+thing 3005 m -  31 "Cacodemon"			HEAD
+thing    7 m - 128 "Spider mastermind"		SPID
+thing   16 m -  40 "Cyberdemon"			CYBR
+thing 7101 m -  64 "Imp spawner [EDGE]"		TFOGB
+
+thing    1 p -  16 "Player 1 start"		PLAY
+thing    2 p -  16 "Player 2 start"		PLAY
+thing    3 p -  16 "Player 3 start"		PLAY
+thing    4 p -  16 "Player 4 start"		PLAY
+thing  888 p -  12 "Dog [MBF]"
+thing   11 p -  16 "Deathmatch start"		PLAYF1
+thing   14 p -  16 "Teleport exit"		TFOG
+
+thing 2005 w -  20 "Chainsaw"			CSAW
+thing 2001 w -  20 "Shotgun"			SHOT
+thing 2002 w -  20 "Chaingun"			MGUN
+thing 2003 w -  20 "Rocket launcher"		LAUN
+thing 2004 w -  20 "Plasma gun"			PLAS
+thing 2006 w -  20 "BFG9000"			BFUG
+
+thing 5001 s -  20 "Point pusher [Boom]"
+thing 5002 s -  20 "Point puller [Boom]"
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ygd/doom02.ygd	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,352 @@
+# Yadex game definition file version 4
+#
+#	doom02.ygd
+#	Yadex Game Definitions for Doom alpha 0.2
+#	See doc/ygd.html for the specs.
+#	AYM 1999-07-09
+#
+
+# FIXME probably needs work, especially in
+# the things definitions dept.
+
+level_format    alpha		# FIXME it's not even that !
+level_name      e1m1		# FIXME it's not even that !
+picture_format  alpha
+sky_flat        f_sky1
+texture_lumps   none
+
+#
+#	Definition of linedef type groups
+#	Format is : ldtgroup <ldtgroup> <description>
+#
+
+ldtgroup d "Door"
+ldtgroup r "Door (red key)"
+ldtgroup y "Door (yellow key)"
+ldtgroup b "Door (blue key)"
+ldtgroup D "Door (turbo)"
+ldtgroup l "Lift"
+ldtgroup F "Floor (raise)"
+ldtgroup f "Floor (lower)"
+ldtgroup c "Ceiling"
+ldtgroup C "Crushing ceiling"
+ldtgroup t "Teleport"
+ldtgroup L "Light"
+ldtgroup e "End level"
+ldtgroup m "Moving floor"
+ldtgroup s "Raising stairs"
+ldtgroup x "Misc."
+
+#
+#	Definition of linedef types
+#	Format is : ldt <number> <ldtgroup> <shortdesc> <longdesc>
+#	<shortdesc> must not exceed 16 characters.
+#
+
+ldt   0 x "-- Normal"        "--  Normal"
+ldt   1 d "DR Open door"     "DR  Open  door"
+ldt   2 d "W1 Open door (O)" "W1  Open  door (stays open)"
+ldt   3 d "W1 Close door"    "W1  Close door"
+ldt   4 d "W1 Open door"     "W1  Open  door"
+ldt   5 F "W1 Floor up LIC"  "W1  Raise floor to LIC"
+ldt   6 C "W1 Crush FF"      "W1  Start fast crushing, fast hurt"
+ldt   7 s "S1 Raise stairs"  "S1  Raise stairs (several sectors 0/999)"
+ldt   8 s "W1 Raise stairs"  "W1  Raise stairs (several sectors 0/999)"
+ldt   9 x "S1 Donut"         "S1  Lower floor, raise Ne. floor (NXP) 'Donut'"
+ldt  10 l "W1 Lower lift"    "W1  Lower lift"
+ldt  11 e "S- End level"     "S-  End level, go to next level"
+ldt  12 L "W1 Light to HE"   "W1  Light level goes to HE"
+ldt  13 L "W1 Light to 255"  "W1  Light level goes to 255"
+ldt  14 F "S1& F. up 32 TX"  "S1& Raise floor by 32 (TX)"
+ldt  15 F "S1& F. up 24 TX"  "S1& Raise floor by 24 (TX)"
+ldt  16 d "W1 Close for 30s" "W1  Close door for 30 seconds"
+ldt  17 L "W1 Start blink"   "W1  Start blinking lights"
+ldt  18 F "S1 Floor up nhEF" "S1  Raise floor to nhEF"
+ldt  19 f "W1 Floor dn HEF"  "W1  Lower floor to HEF"
+ldt  20 F "S1& F up nhEF TX" "S1& Raise floor to nhEF (TX)"
+ldt  21 l "S1 Lower lift"    "S1  Lower lift"
+ldt  22 F "W1& F up nhEF TX" "W1& Raise floor to nhEF (TX)"
+ldt  23 f "S1 Floor dn LEF"  "S1  Lower floor to LEF"
+ldt  24 F "G1 Floor up LIC"  "G1  Raise floor to LIC"
+ldt  25 C "W1 Crush FS"      "W1  Start fast crushing, slow hurt"
+ldt  26 b "DR Open blue dr"  "DR  Open  door, blue key"
+ldt  27 y "DR Open yel dr"   "DR  Open  door, yellow key"
+ldt  28 r "DR Open red dr"   "DR  Open  door, red key"
+ldt  29 d "S1 Open door"     "S1  Open  door"
+ldt  30 F "W1 Floor up SLT"  "W1  Raise floor by ShortestLowerTexture"
+ldt  31 d "D1 Open door (O)" "D1  Open  door (stays open)"
+ldt  32 b "D1 Open blu (O)"  "D1  Open  door (stays open), blue key"
+ldt  33 r "D1 Open red (O)"  "D1  Open  door (stays open), red key"
+ldt  34 y "D1 Open yel (O)"  "D1  Open  door (stays open), yellow key"
+ldt  35 L "W1 Light to 35"   "W1  Light level goes to 35"
+ldt  36 f "W1 F. DN HEF+8"   "W1  Lower turbo floor to HEF + 8"
+ldt  37 f "W1 F. dn LEF NXP" "W1  Lower floor to LEF (NXP)"
+ldt  38 f "W1 Floor dn LEF"  "W1  Lower floor to LEF"
+ldt  39 t "W1 Teleport"      "W1  Teleport to another sector"
+ldt  40 c "W1 Ceil up HEC"   "W1  Raise ceiling to HEC"
+ldt  41 c "S1 Ceil dn floor" "S1  Lower ceiling to floor"
+ldt  42 d "SR Close door"    "SR  Close door"
+ldt  43 c "SR Ceil dn floor" "SR  Lower ceiling to floor"
+ldt  44 c "W1 Ceil dn flr+8" "W1  Lower ceiling to floor + 8"
+ldt  45 f "SR Floor dn HEF"  "SR  Lower floor to HEF"
+ldt  46 d "GR Open door (O)" "GR  Open  door (stays open)"
+ldt  47 F "G1 F. up nhEF TX" "G1  Raise floor to nhEF (TX)"
+ldt  48 x "-- Animated wall" "--  Animated wall (scrolls horizontally)"
+ldt  49 c "S1 Ceil dn flr+8" "S1  Lower ceiling to floor + 8"
+ldt  50 d "S1 Close door"    "S1  Close door"
+ldt  51 e "S- Secret level"  "S-  End level, go to secret level"
+ldt  52 e "W- End level"     "W-  End level, go to next level"
+ldt  53 m "W1 Start moving"  "W1  Start moving floor"
+ldt  54 m "W1 Stop moving f" "W1  Stop  moving floor"
+ldt  55 F "S1 F. up LIC-8"   "S1  Raise floor to LIC - 8, crush"
+ldt  56 F "W1& F. up LIC-8"  "W1& Raise floor to LIC - 8, crush"
+ldt  57 C "W1& Stop crush"   "W1& Stop  crushing"
+ldt  58 F "W1 Floor up 24"   "W1  Raise floor by 24"
+ldt  59 F "W1 F. up 24 TXP"  "W1  Raise floor by 24 (TXP)"
+ldt  60 f "SR Floor dn LEF"  "SR  Lower floor to LEF"
+ldt  61 d "SR Open door (O)" "SR  Open  door (stays open)"
+ldt  62 l "SR Lower lift"    "SR  Lower lift"
+ldt  63 d "SR Open door"     "SR  Open  door"
+ldt  64 F "SR Floor up LIC"  "SR  Raise floor to LIC"
+ldt  65 F "SR F. up LIC-8"   "SR  Raise floor to LIC - 8, crush"
+ldt  66 F "SR& F. up 24 TX"  "SR& Raise floor by 24 (TX)"
+ldt  67 F "SR& F. up 32 TX"  "SR& Raise floor by 32 (TX)"
+ldt  68 f "SR& F up nhEF TX" "SR& Raise floor to nhEF (TX)"
+ldt  69 F "SR F. up nhEF"    "SR  Raise floor to nhEF"
+ldt  70 f "SR F. DN HEF+8"   "SR  Lower turbo floor to HEF + 8"
+ldt  71 f "S1 F. DN HEF+8"   "S1  Lower turbo floor to HEF + 8"
+ldt  72 c "WR Ceil dn flr+8" "WR  Lower ceiling to floor + 8"
+ldt  73 C "WR& Crush SS"     "WR& Start slow crushing, slow hurt"
+ldt  74 C "WR& Stop crush"   "WR& Stop  crushing"
+ldt  75 d "WR Close door"    "WR  Close door"
+ldt  76 d "WR Close for 30s" "WR  Close door for 30 seconds"
+ldt  77 C "WR& Crush FF"     "WR& Start fast crushing, fast hurt"
+#ldt 78 x "-- Unimplemented" "--  Unimplemented"
+ldt  79 L "WR Light to 35"   "WR  Light level goes to 35"
+ldt  80 L "WR Light to HE"   "WR  Light level goes to HE"
+ldt  81 L "WR Light to 255"  "WR  Light level goes to 255"
+ldt  82 f "WR Floor dn LEF"  "WR  Lower floor to LEF"
+ldt  83 f "WR Floor dn HEF"  "WR  Lower floor to HEF"
+ldt  84 f "WR F. dn LEF NXP" "WR  Lower floor to LEF (NXP)"
+#ldt 85 x "-- Unimplemented" "--  Unimplemented"
+ldt  86 d "WR Open door (O)" "WR  Open  door (stays open)"
+ldt  87 m "WR& Start moving" "WR& Start moving floor"
+ldt  88 l "WR Lower lift"    "WR  Lower lift"
+ldt  89 m "WR& Stop moving"  "WR& Stop  moving floor"
+ldt  90 d "WR Open door"     "WR  Open  door"
+ldt  91 F "WR Floor up LIC"  "WR  Raise floor to LIC"
+ldt  92 F "WR Floor up 24"   "WR  Raise floor by 24"
+ldt  93 F "WR F. up 24 TXP"  "WR  Raise floor by 24 (TXP)"
+ldt  94 F "WR F. up LIC-8"   "WR  Raise floor to LIC - 8, crush"
+ldt  95 F "WR F. up nhEF TX" "WR  Raise floor to nhEF (TX)"
+ldt  96 F "WR Floor up SLT"  "WR  Raise floor by ShortestLowerTexture"
+ldt  97 t "WR Teleport"      "WR  Teleport to another sector"
+ldt  98 f "WR F. DN HEF+8"   "WR  Lower turbo floor to HEF + 8"
+ldt  99 b "SR OPEN blu door" "SR  Open  turbo door, blue key [v1.6]"
+ldt 100 s "W1 RaiseStairs16" "W1  Raise stairs (step=16), crush [v1.6]"
+ldt 101 F "S1 Floor up LIC"  "S1  Raise floor to LIC"
+ldt 102 f "S1 Floor dn HEF"  "S1  Lower floor to HEF"
+ldt 103 d "S1 Open door (O)" "S1  Open  door (stays open)"
+ldt 104 L "W1 Light to LE"   "W1  Light level goes to LE"
+ldt 105 D "WR OPEN door"     "WR  Open  turbo door [v1.6]"
+ldt 106 D "WR OPEN door (O)" "WR  Open  turbo door (stays open) [v1.6]"
+ldt 107 D "WR CLOSE door"    "WR  Close turbo door [v1.6]"
+ldt 108 D "W1 OPEN door"     "W1  Open  turbo door [v1.6]"
+ldt 109 D "W1 OPEN door (O)" "W1  Open  turbo door (stays open) [v1.6]"
+ldt 110 D "W1 CLOSE door"    "W1  Close turbo door [v1.6]"
+ldt 111 D "S1 OPEN door"     "S1  Open  turbo door [v1.6]"
+ldt 112 D "S1 OPEN door (O)" "S1  Open  turbo door (stays open) [v1.6]"
+ldt 113 D "S1 CLOSE door"    "S1  Close turbo door [v1.6]"
+ldt 114 D "SR OPEN door"     "SR  Open  turbo door [v1.6]"
+ldt 115 D "SR OPEN door (O)" "SR  Open  turbo door (stays open) [v1.6]"
+ldt 116 D "SR CLOSE door"    "SR  Close turbo door [v1.6]"
+ldt 117 D "DR OPEN door"     "DR  Open  turbo door [v1.6]"
+ldt 118 D "D1 OPEN door (O)" "D1  Open  turbo door (stays open) [v1.6]"
+ldt 119 F "W1 Floor up nhEF" "W1  Raise floor to nhEF [v1.6]"
+ldt 120 l "WR LOWER lift"    "WR  Lower turbo lift [v1.6]"
+ldt 121 l "W1 LOWER lift"    "W1  Lower turbo lift [v1.6]"
+ldt 122 l "S1 LOWER lift"    "S1  Lower turbo lift [v1.6]"
+ldt 123 l "SR LOWER lift"    "SR  Lower turbo lift [v1.6]"
+ldt 124 e "W- Secret level"  "W-  End level, go to secret level [v1.6]"
+ldt 125 t "W1 Teleport mons" "W1  Teleport monsters only [v1.6]"
+ldt 126 t "WR Teleport mons" "WR  Teleport monsters only [v1.6]"
+ldt 127 s "S1 RaiseStairs16" "S1  Raise stairs (step=16), crush [v1.6]"
+ldt 128 F "WR Floor up nhEF" "WR  Raise floor to nhEF [v1.6]"
+ldt 129 F "WR Floor UP nhEF" "WR  Raise turbo floor to nhEF [v1.6]"
+ldt 130 F "W1 Floor UP nhEF" "W1  Raise turbo floor to nhEF [v1.6]"
+ldt 131 F "S1 Floor UP nhEF" "S1  Raise turbo floor to nhEF [v1.6]"
+ldt 132 F "SR Floor UP nhEF" "SR  Raise turbo floor to nhEF [v1.6]"
+ldt 133 b "S1 OPEN blu door" "S1  Open  turbo door, blue key [v1.6]"
+ldt 134 r "SR OPEN red door" "SR  Open  turbo door, red key [v1.6]"
+ldt 135 r "S1 OPEN red door" "S1  Open  turbo door, red key [v1.6]"
+ldt 136 y "SR OPEN yel door" "SR  Open  turbo door, yellow key [v1.6]"
+ldt 137 y "S1 OPEN yel door" "S1  Open  turbo door, yellow key [v1.6]"
+ldt 138 L "SR Light to 255"  "SR  Light level goes to 255 [v1.6]"
+ldt 139 L "SR Light to 0"    "SR  Light level goes to 0 [v1.6]"
+ldt 140 F "S1 Floor up 512"  "S1  Raise floor by 512, medium speed [v1.6]"
+ldt 141 C "W1& Crush SS sil" "W1& Start slow crushing, slow hurt, silent [v1.6]"
+ldt 271 x "-- Xfer sky"      "--  Xfer straight upper to sky tex. [MBF]"
+ldt 272 x "-- Xfer mir. sky" "--  Xfer mirrored upper to sky tex. [MBF]"
+
+#
+#	Definition of sector types
+#	Format is : st <number> <shortdesc> <longdesc>
+#	<shortdesc> must not exceed 14 characters.
+#
+
+st  0 "X Normal"       "X Normal"
+st  1 "  Blinks rand"  "  Light blinks randomly"
+st  2 "  Flashes 2 Hz" "  Light flashes 2 Hz"
+st  3 "  Flashes 1 Hz" "  Light flashes 1 Hz"
+st  4 "P -20% & 2Hz"   "P -10/20% health, flashes 2 Hz"
+st  5 "P -10% health"  "P -5/10% health"
+st  7 "P -5% health"   "P -2/5% health"
+st  8 "  Oscillates"   "  Light oscillates"
+st  9 "P Secret"       "P Secret"
+st 10 "  Closes 30 s"  "  30 s after level start, ceiling closes like a door"
+st 11 "P -20% & end"   "P -10/20% health and end level when health <= 10%"
+st 12 "  Flash1Hz syn" "  Light flashes 1 Hz, synchronized"
+st 13 "  Flash2Hz syn" "  Light flashes 2 Hz, synchronized"
+st 14 "  Opens 300 s"  "  300 s after level start, ceiling opens like a door"
+st 16 "P -20% health"  "P -10/20% health"
+st 17 "  Flicker rand" "  Light flickers on and off randomly [v1.6]"
+
+#
+#	Definition of thing groups
+#	Format is : thinggroup <thinggroup> <colour> <description>
+#
+
+thinggroup p rgb:4/f/4 "Player"
+thinggroup m rgb:f/0/0 "Monster"
+thinggroup w rgb:f/a/0 "Weapon"
+thinggroup a rgb:8/5/0 "Ammunition"
+thinggroup h rgb:2/8/0 "Health & armour"
+thinggroup b rgb:2/8/0 "Misc. bonus"
+thinggroup k rgb:f/0/f "Key"
+thinggroup d rgb:6/6/c "Misc. decoration"
+thinggroup l rgb:6/6/c "Light source"
+thinggroup g rgb:6/6/c "Gory decoration"
+thinggroup c rgb:6/6/c "Corpse"
+thinggroup s rgb:0/b/d "Special"
+
+#
+#	Definition of things
+#	Format is :
+#	thing <number> <thinggroup> <flags> <radius> <desc> [<sprite>]
+#	<desc> must not exceed 19 characters.
+#
+
+thing 2007 a -  20 "Clip"			CLIP
+thing 2048 a -  20 "Box of bullets"		AMMO
+thing 2008 a -  20 "4 shotgun shells"		SHEL
+thing 2049 a -  20 "Box shotgun shells"		SBOX
+thing 2010 a -  20 "Rocket"			ROCK
+thing 2046 a -  20 "Box of rockets"		BROK
+thing 2047 a -  20 "Energy cell"		CELL
+thing   17 a -  20 "Energy cell pack"		CELP
+thing    8 a -  20 "Backpack full ammo"		BPAK
+
+thing 2025 b -  20 "Rad. shielding suit"	SUIT
+thing 2026 b -  20 "Computer area map"		PMAP
+thing 2024 b -  20 "Partial invis."		PINS
+thing 2023 b -  20 "Berserk"			PSTR
+thing 2022 b -  20 "Invulnerability"		PINV
+thing 2045 b -  20 "Light amp. visor"		PVIS
+thing 2016 b -  16 "Evil sceptre"		BON3
+thing 2017 b -  16 "Unholy bible"		BON4
+
+thing   15 c -  16 "Dead player (green)"	PLAYN
+thing   18 c -  20 "Dead trooper"		POSSL
+thing   19 c -  20 "Dead sergeant"		SPOSL
+thing   20 c -  20 "Dead imp"			TROOM
+thing   21 c -  16 "Dead demon"			SARGN
+thing   22 c -  16 "Dead cacodemon"		HEADL
+thing   23 c -  16 "Dead lost soul"		SKULK
+
+thing 2035 d -  10 "Barrel"			BAR1
+thing   48 d -  16 "Technical column"		ELEC
+thing   30 d -  16 "Tall green pillar"		COL1
+thing   32 d -  16 "Tall red pillar"		COL3
+thing   31 d -  16 "Short green pillar"		COL2
+thing   33 d -  16 "Short red pillar"		COL4
+thing   36 d -  16 "Pillar w/heart"		COL5
+thing   37 d -  16 "Red pillar w/skull"		COL6
+thing   41 d -  16 "Evil eye"			CEYE
+thing   42 g -  16 "Floating skulls"		FSKU
+thing   43 d -  16 "Grey tree"			TRE1
+thing   47 d -  16 "Brown stub"			SMIT
+thing   54 d -  32 "Tall brown tree"		TRE2
+
+thing   10 g -  16 "Mushed player"		PLAYW
+thing   12 g -  16 "Mushed player 2"		PLAYW
+thing   24 g -  16 "Pool of blood"		POL5
+thing   27 g -  16 "Pole with skull"		POL4
+thing   28 g -  16 "Skewer with heads"		POL2
+thing   29 g -  16 "Pile of skulls"		POL3
+thing   25 g -  16 "Impaled body"		POL1
+thing   26 g -  16 "Impaled twitching"		POL6
+thing   49 g -  16 "Swaying body O"		GOR1
+thing   63 g -  16 "Swaying body"		GOR1
+thing   50 g -  16 "Hanging arms out O"		GOR2
+thing   59 g -  16 "Hanging arms out"		GOR2
+thing   53 g -  16 "Hanging leg O"		GOR5
+thing   62 g -  16 "Hanging leg"		GOR5
+thing   51 g -  16 "Hanging one-legged O"	GOR3	# FIXME cut off
+thing   61 g -  16 "Hanging one-legged"		GOR3
+thing   52 g -  16 "Hanging torso O"		GOR4
+thing   60 g -  16 "Hanging torso"		GOR4
+
+thing 2014 h -  20 "Health bonus"		BON1
+thing 2011 h -  20 "Stimpack"			STIM
+thing 2012 h -  20 "Medikit"			MEDI
+thing 2013 h -  20 "Supercharge"		SOUL
+thing 2015 h -  20 "Armor bonus"		BON2
+thing 2018 h -  20 "Armor"			ARM1
+thing 2019 h -  20 "Megaarmor"			ARM2
+
+thing    5 k -  20 "Blue key"			GKEY
+thing    6 k -  20 "Yellow key"			SKEY
+thing    7 k -  20 "Red key"			BKEY
+thing   40 k -  20 "Blue skull key"		BSKU
+thing   39 k -  20 "Yellow skull key"		YSKU
+thing   38 k -  20 "Red skull key"		RSKU
+
+thing 2028 l -  16 "Lamp"			COLU
+thing   34 l -  16 "Candle"			CAND
+thing   35 l -  16 "Candelabra"			CBRA
+thing   44 l -  16 "Tall blue torch"		TBLU
+thing   45 l -  16 "Tall green torch"		TGRN
+thing   46 l -  16 "Tall red torch"		TRED
+thing   55 l -  16 "Short blue torch"		SMBT
+thing   56 l -  16 "Short green torch"		SMGT
+thing   57 l -  16 "Short red torch"		SMRT
+
+thing 3004 m -  20 "Trooper"			POSS
+thing    9 m -  20 "Sergeant"			SPOS
+thing 3001 m -  20 "Imp"			TROO
+thing 3002 m -  30 "Demon"			SARG
+thing 3003 m -  24 "Baron of hell"		BOSS
+thing   58 m s  30 "Spectre"			SARG
+thing 3006 m -  16 "Lost soul"			SKUL
+thing 3005 m -  31 "Cacodemon"			HEAD
+thing    7 m - 128 "Spider mastermind"		SPID
+thing   16 m -  40 "Cyberdemon"			CYBR
+
+thing    1 p -  16 "Player 1 start"		PLAY
+thing    2 p -  16 "Player 2 start"		PLAY
+thing    3 p -  16 "Player 3 start"		PLAY
+thing    4 p -  16 "Player 4 start"		PLAY
+thing  888 p -  12 "Dog [MBF]"
+thing   11 p -  16 "Deathmatch start"		PLAYF1
+thing   14 p -  16 "Teleport exit"		TFOG
+
+thing 2005 w -  20 "Chainsaw"			CSAW
+thing 2001 w -  20 "Shotgun"			SHOT
+thing 2002 w -  20 "Chaingun"			MGUN
+thing 2003 w -  20 "Rocket launcher"		LAUN
+thing 2004 w -  20 "Plasma gun"			PLAS
+thing 2006 w -  20 "BFG9000"			BFUG
+
+thing 5001 s -  20 "Point pusher [Boom]"
+thing 5002 s -  20 "Point puller [Boom]"
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ygd/doom04.ygd	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,362 @@
+# Yadex game definition file version 4
+#
+#	doom04.ygd
+#	Yadex Game Definitions for Doom alpha 0.4
+#	See doc/ygd.html for the specs.
+#	AYM 1999-07-09
+#
+
+# FIXME probably needs work, especially in
+# the things definitions dept.
+
+level_format    alpha
+level_name      e1m10
+picture_format  alpha
+sky_flat        f_sky1
+texture_format  nameless
+texture_lumps   textures
+
+#
+#	Definition of linedef type groups
+#	Format is : ldtgroup <ldtgroup> <description>
+#
+
+ldtgroup d "Door"
+ldtgroup r "Door (red key)"
+ldtgroup y "Door (yellow key)"
+ldtgroup b "Door (blue key)"
+ldtgroup D "Door (turbo)"
+ldtgroup l "Lift"
+ldtgroup F "Floor (raise)"
+ldtgroup f "Floor (lower)"
+ldtgroup c "Ceiling"
+ldtgroup C "Crushing ceiling"
+ldtgroup t "Teleport"
+ldtgroup L "Light"
+ldtgroup e "End level"
+ldtgroup m "Moving floor"
+ldtgroup s "Raising stairs"
+ldtgroup x "Misc."
+
+#
+#	Definition of linedef types
+#	Format is : ldt <number> <ldtgroup> <shortdesc> <longdesc>
+#	<shortdesc> must not exceed 16 characters.
+#
+
+ldt   0 x "-- Normal"        "--  Normal"
+ldt   1 d "DR Open door"     "DR  Open  door"
+ldt   2 d "W1 Open door (O)" "W1  Open  door (stays open)"
+ldt   3 d "W1 Close door"    "W1  Close door"
+ldt   4 d "W1 Open door"     "W1  Open  door"
+ldt   5 F "W1 Floor up LIC"  "W1  Raise floor to LIC"
+ldt   6 C "W1 Crush FF"      "W1  Start fast crushing, fast hurt"
+ldt   7 s "S1 Raise stairs"  "S1  Raise stairs (several sectors 0/999)"
+ldt   8 s "W1 Raise stairs"  "W1  Raise stairs (several sectors 0/999)"
+ldt   9 x "S1 Donut"         "S1  Lower floor, raise Ne. floor (NXP) 'Donut'"
+ldt  10 l "W1 Lower lift"    "W1  Lower lift"
+ldt  11 e "S- End level"     "S-  End level, go to next level"
+ldt  12 L "W1 Light to HE"   "W1  Light level goes to HE"
+ldt  13 L "W1 Light to 255"  "W1  Light level goes to 255"
+ldt  14 F "S1& F. up 32 TX"  "S1& Raise floor by 32 (TX)"
+ldt  15 F "S1& F. up 24 TX"  "S1& Raise floor by 24 (TX)"
+ldt  16 d "W1 Close for 30s" "W1  Close door for 30 seconds"
+ldt  17 L "W1 Start blink"   "W1  Start blinking lights"
+ldt  18 F "S1 Floor up nhEF" "S1  Raise floor to nhEF"
+ldt  19 f "W1 Floor dn HEF"  "W1  Lower floor to HEF"
+ldt  20 F "S1& F up nhEF TX" "S1& Raise floor to nhEF (TX)"
+ldt  21 l "S1 Lower lift"    "S1  Lower lift"
+ldt  22 F "W1& F up nhEF TX" "W1& Raise floor to nhEF (TX)"
+ldt  23 f "S1 Floor dn LEF"  "S1  Lower floor to LEF"
+ldt  24 F "G1 Floor up LIC"  "G1  Raise floor to LIC"
+ldt  25 C "W1 Crush FS"      "W1  Start fast crushing, slow hurt"
+ldt  26 b "DR Open blue dr"  "DR  Open  door, blue key"
+ldt  27 y "DR Open yel dr"   "DR  Open  door, yellow key"
+ldt  28 r "DR Open red dr"   "DR  Open  door, red key"
+ldt  29 d "S1 Open door"     "S1  Open  door"
+ldt  30 F "W1 Floor up SLT"  "W1  Raise floor by ShortestLowerTexture"
+ldt  31 d "D1 Open door (O)" "D1  Open  door (stays open)"
+ldt  32 b "D1 Open blu (O)"  "D1  Open  door (stays open), blue key"
+ldt  33 r "D1 Open red (O)"  "D1  Open  door (stays open), red key"
+ldt  34 y "D1 Open yel (O)"  "D1  Open  door (stays open), yellow key"
+ldt  35 L "W1 Light to 35"   "W1  Light level goes to 35"
+ldt  36 f "W1 F. DN HEF+8"   "W1  Lower turbo floor to HEF + 8"
+ldt  37 f "W1 F. dn LEF NXP" "W1  Lower floor to LEF (NXP)"
+ldt  38 f "W1 Floor dn LEF"  "W1  Lower floor to LEF"
+ldt  39 t "W1 Teleport"      "W1  Teleport to another sector"
+ldt  40 c "W1 Ceil up HEC"   "W1  Raise ceiling to HEC"
+ldt  41 c "S1 Ceil dn floor" "S1  Lower ceiling to floor"
+ldt  42 d "SR Close door"    "SR  Close door"
+ldt  43 c "SR Ceil dn floor" "SR  Lower ceiling to floor"
+ldt  44 c "W1 Ceil dn flr+8" "W1  Lower ceiling to floor + 8"
+ldt  45 f "SR Floor dn HEF"  "SR  Lower floor to HEF"
+ldt  46 d "GR Open door (O)" "GR  Open  door (stays open)"
+ldt  47 F "G1 F. up nhEF TX" "G1  Raise floor to nhEF (TX)"
+ldt  48 x "-- Animated wall" "--  Animated wall (scrolls horizontally)"
+ldt  49 c "S1 Ceil dn flr+8" "S1  Lower ceiling to floor + 8"
+ldt  50 d "S1 Close door"    "S1  Close door"
+ldt  51 e "S- Secret level"  "S-  End level, go to secret level"
+ldt  52 e "W- End level"     "W-  End level, go to next level"
+ldt  53 m "W1 Start moving"  "W1  Start moving floor"
+ldt  54 m "W1 Stop moving f" "W1  Stop  moving floor"
+ldt  55 F "S1 F. up LIC-8"   "S1  Raise floor to LIC - 8, crush"
+ldt  56 F "W1& F. up LIC-8"  "W1& Raise floor to LIC - 8, crush"
+ldt  57 C "W1& Stop crush"   "W1& Stop  crushing"
+ldt  58 F "W1 Floor up 24"   "W1  Raise floor by 24"
+ldt  59 F "W1 F. up 24 TXP"  "W1  Raise floor by 24 (TXP)"
+ldt  60 f "SR Floor dn LEF"  "SR  Lower floor to LEF"
+ldt  61 d "SR Open door (O)" "SR  Open  door (stays open)"
+ldt  62 l "SR Lower lift"    "SR  Lower lift"
+ldt  63 d "SR Open door"     "SR  Open  door"
+ldt  64 F "SR Floor up LIC"  "SR  Raise floor to LIC"
+ldt  65 F "SR F. up LIC-8"   "SR  Raise floor to LIC - 8, crush"
+ldt  66 F "SR& F. up 24 TX"  "SR& Raise floor by 24 (TX)"
+ldt  67 F "SR& F. up 32 TX"  "SR& Raise floor by 32 (TX)"
+ldt  68 f "SR& F up nhEF TX" "SR& Raise floor to nhEF (TX)"
+ldt  69 F "SR F. up nhEF"    "SR  Raise floor to nhEF"
+ldt  70 f "SR F. DN HEF+8"   "SR  Lower turbo floor to HEF + 8"
+ldt  71 f "S1 F. DN HEF+8"   "S1  Lower turbo floor to HEF + 8"
+ldt  72 c "WR Ceil dn flr+8" "WR  Lower ceiling to floor + 8"
+ldt  73 C "WR& Crush SS"     "WR& Start slow crushing, slow hurt"
+ldt  74 C "WR& Stop crush"   "WR& Stop  crushing"
+ldt  75 d "WR Close door"    "WR  Close door"
+ldt  76 d "WR Close for 30s" "WR  Close door for 30 seconds"
+ldt  77 C "WR& Crush FF"     "WR& Start fast crushing, fast hurt"
+#ldt 78 x "-- Unimplemented" "--  Unimplemented"
+ldt  79 L "WR Light to 35"   "WR  Light level goes to 35"
+ldt  80 L "WR Light to HE"   "WR  Light level goes to HE"
+ldt  81 L "WR Light to 255"  "WR  Light level goes to 255"
+ldt  82 f "WR Floor dn LEF"  "WR  Lower floor to LEF"
+ldt  83 f "WR Floor dn HEF"  "WR  Lower floor to HEF"
+ldt  84 f "WR F. dn LEF NXP" "WR  Lower floor to LEF (NXP)"
+#ldt 85 x "-- Unimplemented" "--  Unimplemented"
+ldt  86 d "WR Open door (O)" "WR  Open  door (stays open)"
+ldt  87 m "WR& Start moving" "WR& Start moving floor"
+ldt  88 l "WR Lower lift"    "WR  Lower lift"
+ldt  89 m "WR& Stop moving"  "WR& Stop  moving floor"
+ldt  90 d "WR Open door"     "WR  Open  door"
+ldt  91 F "WR Floor up LIC"  "WR  Raise floor to LIC"
+ldt  92 F "WR Floor up 24"   "WR  Raise floor by 24"
+ldt  93 F "WR F. up 24 TXP"  "WR  Raise floor by 24 (TXP)"
+ldt  94 F "WR F. up LIC-8"   "WR  Raise floor to LIC - 8, crush"
+ldt  95 F "WR F. up nhEF TX" "WR  Raise floor to nhEF (TX)"
+ldt  96 F "WR Floor up SLT"  "WR  Raise floor by ShortestLowerTexture"
+ldt  97 t "WR Teleport"      "WR  Teleport to another sector"
+ldt  98 f "WR F. DN HEF+8"   "WR  Lower turbo floor to HEF + 8"
+ldt  99 b "SR OPEN blu door" "SR  Open  turbo door, blue key [v1.6]"
+ldt 100 s "W1 RaiseStairs16" "W1  Raise stairs (step=16), crush [v1.6]"
+ldt 101 F "S1 Floor up LIC"  "S1  Raise floor to LIC"
+ldt 102 f "S1 Floor dn HEF"  "S1  Lower floor to HEF"
+ldt 103 d "S1 Open door (O)" "S1  Open  door (stays open)"
+ldt 104 L "W1 Light to LE"   "W1  Light level goes to LE"
+ldt 105 D "WR OPEN door"     "WR  Open  turbo door [v1.6]"
+ldt 106 D "WR OPEN door (O)" "WR  Open  turbo door (stays open) [v1.6]"
+ldt 107 D "WR CLOSE door"    "WR  Close turbo door [v1.6]"
+ldt 108 D "W1 OPEN door"     "W1  Open  turbo door [v1.6]"
+ldt 109 D "W1 OPEN door (O)" "W1  Open  turbo door (stays open) [v1.6]"
+ldt 110 D "W1 CLOSE door"    "W1  Close turbo door [v1.6]"
+ldt 111 D "S1 OPEN door"     "S1  Open  turbo door [v1.6]"
+ldt 112 D "S1 OPEN door (O)" "S1  Open  turbo door (stays open) [v1.6]"
+ldt 113 D "S1 CLOSE door"    "S1  Close turbo door [v1.6]"
+ldt 114 D "SR OPEN door"     "SR  Open  turbo door [v1.6]"
+ldt 115 D "SR OPEN door (O)" "SR  Open  turbo door (stays open) [v1.6]"
+ldt 116 D "SR CLOSE door"    "SR  Close turbo door [v1.6]"
+ldt 117 D "DR OPEN door"     "DR  Open  turbo door [v1.6]"
+ldt 118 D "D1 OPEN door (O)" "D1  Open  turbo door (stays open) [v1.6]"
+ldt 119 F "W1 Floor up nhEF" "W1  Raise floor to nhEF [v1.6]"
+ldt 120 l "WR LOWER lift"    "WR  Lower turbo lift [v1.6]"
+ldt 121 l "W1 LOWER lift"    "W1  Lower turbo lift [v1.6]"
+ldt 122 l "S1 LOWER lift"    "S1  Lower turbo lift [v1.6]"
+ldt 123 l "SR LOWER lift"    "SR  Lower turbo lift [v1.6]"
+ldt 124 e "W- Secret level"  "W-  End level, go to secret level [v1.6]"
+ldt 125 t "W1 Teleport mons" "W1  Teleport monsters only [v1.6]"
+ldt 126 t "WR Teleport mons" "WR  Teleport monsters only [v1.6]"
+ldt 127 s "S1 RaiseStairs16" "S1  Raise stairs (step=16), crush [v1.6]"
+ldt 128 F "WR Floor up nhEF" "WR  Raise floor to nhEF [v1.6]"
+ldt 129 F "WR Floor UP nhEF" "WR  Raise turbo floor to nhEF [v1.6]"
+ldt 130 F "W1 Floor UP nhEF" "W1  Raise turbo floor to nhEF [v1.6]"
+ldt 131 F "S1 Floor UP nhEF" "S1  Raise turbo floor to nhEF [v1.6]"
+ldt 132 F "SR Floor UP nhEF" "SR  Raise turbo floor to nhEF [v1.6]"
+ldt 133 b "S1 OPEN blu door" "S1  Open  turbo door, blue key [v1.6]"
+ldt 134 r "SR OPEN red door" "SR  Open  turbo door, red key [v1.6]"
+ldt 135 r "S1 OPEN red door" "S1  Open  turbo door, red key [v1.6]"
+ldt 136 y "SR OPEN yel door" "SR  Open  turbo door, yellow key [v1.6]"
+ldt 137 y "S1 OPEN yel door" "S1  Open  turbo door, yellow key [v1.6]"
+ldt 138 L "SR Light to 255"  "SR  Light level goes to 255 [v1.6]"
+ldt 139 L "SR Light to 0"    "SR  Light level goes to 0 [v1.6]"
+ldt 140 F "S1 Floor up 512"  "S1  Raise floor by 512, medium speed [v1.6]"
+ldt 141 C "W1& Crush SS sil" "W1& Start slow crushing, slow hurt, silent [v1.6]"
+ldt 271 x "-- Xfer sky"      "--  Xfer straight upper to sky tex. [MBF]"
+ldt 272 x "-- Xfer mir. sky" "--  Xfer mirrored upper to sky tex. [MBF]"
+
+#
+#	Definition of sector types
+#	Format is : st <number> <shortdesc> <longdesc>
+#	<shortdesc> must not exceed 14 characters.
+#
+
+st  0 "X Normal"       "X Normal"
+st  1 "  Blinks rand"  "  Light blinks randomly"
+st  2 "  Flashes 2 Hz" "  Light flashes 2 Hz"
+st  3 "  Flashes 1 Hz" "  Light flashes 1 Hz"
+st  4 "P -20% & 2Hz"   "P -10/20% health, flashes 2 Hz"
+st  5 "P -10% health"  "P -5/10% health"
+st  7 "P -5% health"   "P -2/5% health"
+st  8 "  Oscillates"   "  Light oscillates"
+st  9 "P Secret"       "P Secret"
+st 10 "  Closes 30 s"  "  30 s after level start, ceiling closes like a door"
+st 11 "P -20% & end"   "P -10/20% health and end level when health <= 10%"
+st 12 "  Flash1Hz syn" "  Light flashes 1 Hz, synchronized"
+st 13 "  Flash2Hz syn" "  Light flashes 2 Hz, synchronized"
+st 14 "  Opens 300 s"  "  300 s after level start, ceiling opens like a door"
+st 16 "P -20% health"  "P -10/20% health"
+st 17 "  Flicker rand" "  Light flickers on and off randomly [v1.6]"
+
+#
+#	Definition of thing groups
+#	Format is : thinggroup <thinggroup> <colour> <description>
+#
+
+thinggroup p rgb:4/f/4 "Player"
+thinggroup m rgb:f/0/0 "Monster"
+thinggroup w rgb:f/a/0 "Weapon"
+thinggroup a rgb:8/5/0 "Ammunition"
+thinggroup h rgb:2/8/0 "Health & armour"
+thinggroup b rgb:2/8/0 "Misc. bonus"
+thinggroup k rgb:f/0/f "Key"
+thinggroup d rgb:6/6/c "Misc. decoration"
+thinggroup l rgb:6/6/c "Light source"
+thinggroup g rgb:6/6/c "Gory decoration"
+thinggroup c rgb:6/6/c "Corpse"
+thinggroup s rgb:0/b/d "Special"
+
+#
+#	Definition of things
+#	Format is :
+#	thing <number> <thinggroup> <flags> <radius> <desc> [<sprite>]
+#	<desc> must not exceed 19 characters.
+#
+
+thing 2007 a -  20 "Clip"			CLIP
+thing 2048 a -  20 "Box of bullets"		AMMO
+thing 2008 a -  20 "4 shotgun shells"		SHEL
+thing 2049 a -  20 "Box shotgun shells"		SBOX
+thing 2010 a -  20 "Rocket"			ROCK
+thing 2046 a -  20 "Box of rockets"		MISL
+thing 2047 a -  20 "Energy cell"		CELL
+thing 2020 a -  16 "Energy cell ? [Alpha]"	SHI1
+thing   17 a -  20 "Energy cell pack"		CELP
+thing    8 a -  20 "Backpack full ammo"		BPAK
+
+thing 2025 b -  20 "Rad. shielding suit"	SUIT
+thing 2026 b -  20 "Computer area map"		PMAP
+thing 2024 b -  20 "Partial invis."		PINS
+thing 2023 b -  20 "Berserk"			PSTR
+thing 2022 b -  20 "Invulnerability"		PINV
+thing 2045 b -  20 "Light amp. visor"		PVIS
+thing 2016 b -  16 "Evil sceptre"		BON3
+thing 2017 b -  16 "Unholy bible"		BON4
+
+thing   15 c -  16 "Dead player (green)"	PLAYN
+thing   18 c -  20 "Dead trooper"		POSSL
+thing   19 c -  20 "Dead sergeant"		SPOSL
+thing   20 c -  20 "Dead imp"			TROOM
+thing   21 c -  16 "Dead demon"			SARGN
+thing   22 c -  16 "Dead cacodemon"		HEADL
+thing   23 c -  16 "Dead lost soul"		SKULK
+
+#thing 2021 d -  16 "Unknown [Alpha]"
+thing 2027 d -  10 "Bronze barrel [Alpha]"	GBAR
+thing 2029 d -  16 "Whatever [Alpha]"		FLG
+thing 2030 d -  16 "Whatever [Alpha]"		FLG
+#thing 2032 d -  16 "Unknown [Alpha]"
+thing 2035 d -  10 "Steel barrel"		BBAR
+thing 2036 d -  16 "Chair [Alpha]"		CHAI
+#thing 2037 d -  16 "Unknown [Alpha]"
+thing 2038 d -  16 "Cannister [Alpha]"		CANI
+thing   48 d -  16 "Technical column"		ELEC
+thing   30 d -  16 "Tall green pillar"		COL1
+thing   32 d -  16 "Tall red pillar"		COL3
+thing   31 d -  16 "Short green pillar"		COL2
+thing   33 d -  16 "Short red pillar"		COL4
+thing   36 d -  16 "Pillar w/heart"		COL5
+thing   37 d -  16 "Red pillar w/skull"		COL6
+thing   41 d -  16 "Evil eye"			CEYE
+thing   42 g -  16 "Floating skulls"		FSKU
+thing   43 d -  16 "Grey tree"			TRE1
+thing   47 d -  16 "Brown stub"			SMIT
+thing   54 d -  32 "Tall brown tree"		TRE2
+
+thing   10 g -  16 "Mushed player"		PLAYW
+thing   12 g -  16 "Mushed player 2"		PLAYW
+thing   24 g -  16 "Pool of blood"		POL5
+thing   27 g -  16 "Pole with skull"		POL4
+thing   28 g -  16 "Skewer with heads"		POL2
+thing   29 g -  16 "Pile of skulls"		POL3
+thing   25 g -  16 "Impaled body"		POL1
+thing   26 g -  16 "Impaled twitching"		POL6
+thing   49 g -  16 "Swaying body O"		GOR1
+thing   63 g -  16 "Swaying body"		GOR1
+thing   50 g -  16 "Hanging arms out O"		GOR2
+thing   59 g -  16 "Hanging arms out"		GOR2
+thing   53 g -  16 "Hanging leg O"		GOR5
+thing   62 g -  16 "Hanging leg"		GOR5
+thing   51 g -  16 "Hanging one-legged O"	GOR3	# FIXME cut off
+thing   61 g -  16 "Hanging one-legged"		GOR3
+thing   52 g -  16 "Hanging torso O"		GOR4
+thing   60 g -  16 "Hanging torso"		GOR4
+
+thing 2014 h -  20 "Health bonus"		BON1
+thing 2011 h -  20 "Stimpack"			STIM
+thing 2012 h -  20 "Medikit"			MEDI
+thing 2013 h -  20 "Supercharge"		SOUL
+thing 2015 h -  20 "Armor bonus"		BON2
+thing 2018 h -  20 "Armor"			ARM1
+thing 2019 h -  20 "Megaarmor"			ARM2
+
+thing    5 k -  20 "Blue key"			GKEY
+thing    6 k -  20 "Yellow key"			SKEY
+thing    7 k -  20 "Red key"			BKEY
+thing   40 k -  20 "Blue skull key"		BSKU
+thing   39 k -  20 "Yellow skull key"		YSKU
+thing   38 k -  20 "Red skull key"		RSKU
+
+thing 2028 l -  16 "Lamp"			COLU
+thing   34 l -  16 "Candle"			CAND
+thing   35 l -  16 "Candelabra"			CBRA
+thing   44 l -  16 "Tall blue torch"		TBLU
+thing   45 l -  16 "Tall green torch"		TGRN
+thing   46 l -  16 "Tall red torch"		TRED
+thing   55 l -  16 "Short blue torch"		SMBT
+thing   56 l -  16 "Short green torch"		SMGT
+thing   57 l -  16 "Short red torch"		SMRT
+
+thing 3004 m -  20 "Trooper"			POSS
+thing    9 m -  20 "Sergeant"			SPOS
+thing 3001 m -  20 "Imp"			TROO
+thing 3002 m -  30 "Demon"			SARG
+thing 3003 m -  24 "Baron of hell"		BOSS
+thing   58 m s  30 "Spectre"			SARG
+thing 3006 m -  16 "Lost soul"			SKUL
+thing 3005 m -  31 "Cacodemon"			HEAD
+thing    7 m - 128 "Spider mastermind"		SPID
+thing   16 m -  40 "Cyberdemon"			CYBR
+
+thing    1 p -  16 "Player 1 start"		PLAY
+thing    2 p -  16 "Player 2 start"		PLAY
+thing    3 p -  16 "Player 3 start"		PLAY
+thing    4 p -  16 "Player 4 start"		PLAY
+thing  888 p -  12 "Dog [MBF]"
+thing   11 p -  16 "Deathmatch start"		PLAYF1
+thing   14 p -  16 "Teleport exit"		TFOG
+
+thing 2005 w -  20 "Chainsaw"			CSAW
+thing 2001 w -  20 "Shotgun"			SHOT
+thing 2002 w -  20 "Chaingun"			MGUN
+thing 2003 w -  20 "Rocket launcher"		LAUN
+thing 2004 w -  20 "Plasma gun"			PLAS
+thing 2006 w -  20 "BFG9000"			BFUG
+
+thing 5001 s -  20 "Point pusher [Boom]"
+thing 5002 s -  20 "Point puller [Boom]"
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ygd/doom05.ygd	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,363 @@
+# Yadex game definition file version 4
+#
+#	doom05.ygd
+#	Yadex Game Definitions for Doom alpha 0.5
+#	See doc/ygd.html for the specs.
+#	AYM 1999-07-09
+#
+
+# FIXME probably needs work, especially in
+# the things definitions dept.
+
+level_format    alpha
+level_name      e1m10
+picture_format  alpha
+sky_flat        f_sky1
+texture_format  normal
+texture_lumps   textures
+
+#
+#	Definition of linedef type groups
+#	Format is : ldtgroup <ldtgroup> <description>
+#
+
+ldtgroup d "Door"
+ldtgroup r "Door (red key)"
+ldtgroup y "Door (yellow key)"
+ldtgroup b "Door (blue key)"
+ldtgroup D "Door (turbo)"
+ldtgroup l "Lift"
+ldtgroup F "Floor (raise)"
+ldtgroup f "Floor (lower)"
+ldtgroup c "Ceiling"
+ldtgroup C "Crushing ceiling"
+ldtgroup t "Teleport"
+ldtgroup L "Light"
+ldtgroup e "End level"
+ldtgroup m "Moving floor"
+ldtgroup s "Raising stairs"
+ldtgroup x "Misc."
+
+#
+#	Definition of linedef types
+#	Format is : ldt <number> <ldtgroup> <shortdesc> <longdesc>
+#	<shortdesc> must not exceed 16 characters.
+#
+
+ldt   0 x "-- Normal"        "--  Normal"
+ldt   1 d "DR Open door"     "DR  Open  door"
+ldt   2 d "W1 Open door (O)" "W1  Open  door (stays open)"
+ldt   3 d "W1 Close door"    "W1  Close door"
+ldt   4 d "W1 Open door"     "W1  Open  door"
+ldt   5 F "W1 Floor up LIC"  "W1  Raise floor to LIC"
+ldt   6 C "W1 Crush FF"      "W1  Start fast crushing, fast hurt"
+ldt   7 s "S1 Raise stairs"  "S1  Raise stairs (several sectors 0/999)"
+ldt   8 s "W1 Raise stairs"  "W1  Raise stairs (several sectors 0/999)"
+ldt   9 x "S1 Donut"         "S1  Lower floor, raise Ne. floor (NXP) 'Donut'"
+ldt  10 l "W1 Lower lift"    "W1  Lower lift"
+ldt  11 e "S- End level"     "S-  End level, go to next level"
+ldt  12 L "W1 Light to HE"   "W1  Light level goes to HE"
+ldt  13 L "W1 Light to 255"  "W1  Light level goes to 255"
+ldt  14 F "S1& F. up 32 TX"  "S1& Raise floor by 32 (TX)"
+ldt  15 F "S1& F. up 24 TX"  "S1& Raise floor by 24 (TX)"
+ldt  16 d "W1 Close for 30s" "W1  Close door for 30 seconds"
+ldt  17 L "W1 Start blink"   "W1  Start blinking lights"
+ldt  18 F "S1 Floor up nhEF" "S1  Raise floor to nhEF"
+ldt  19 f "W1 Floor dn HEF"  "W1  Lower floor to HEF"
+ldt  20 F "S1& F up nhEF TX" "S1& Raise floor to nhEF (TX)"
+ldt  21 l "S1 Lower lift"    "S1  Lower lift"
+ldt  22 F "W1& F up nhEF TX" "W1& Raise floor to nhEF (TX)"
+ldt  23 f "S1 Floor dn LEF"  "S1  Lower floor to LEF"
+ldt  24 F "G1 Floor up LIC"  "G1  Raise floor to LIC"
+ldt  25 C "W1 Crush FS"      "W1  Start fast crushing, slow hurt"
+ldt  26 b "DR Open blue dr"  "DR  Open  door, blue key"
+ldt  27 y "DR Open yel dr"   "DR  Open  door, yellow key"
+ldt  28 r "DR Open red dr"   "DR  Open  door, red key"
+ldt  29 d "S1 Open door"     "S1  Open  door"
+ldt  30 F "W1 Floor up SLT"  "W1  Raise floor by ShortestLowerTexture"
+ldt  31 d "D1 Open door (O)" "D1  Open  door (stays open)"
+ldt  32 b "D1 Open blu (O)"  "D1  Open  door (stays open), blue key"
+ldt  33 r "D1 Open red (O)"  "D1  Open  door (stays open), red key"
+ldt  34 y "D1 Open yel (O)"  "D1  Open  door (stays open), yellow key"
+ldt  35 L "W1 Light to 35"   "W1  Light level goes to 35"
+ldt  36 f "W1 F. DN HEF+8"   "W1  Lower turbo floor to HEF + 8"
+ldt  37 f "W1 F. dn LEF NXP" "W1  Lower floor to LEF (NXP)"
+ldt  38 f "W1 Floor dn LEF"  "W1  Lower floor to LEF"
+ldt  39 t "W1 Teleport"      "W1  Teleport to another sector"
+ldt  40 c "W1 Ceil up HEC"   "W1  Raise ceiling to HEC"
+ldt  41 c "S1 Ceil dn floor" "S1  Lower ceiling to floor"
+ldt  42 d "SR Close door"    "SR  Close door"
+ldt  43 c "SR Ceil dn floor" "SR  Lower ceiling to floor"
+ldt  44 c "W1 Ceil dn flr+8" "W1  Lower ceiling to floor + 8"
+ldt  45 f "SR Floor dn HEF"  "SR  Lower floor to HEF"
+ldt  46 d "GR Open door (O)" "GR  Open  door (stays open)"
+ldt  47 F "G1 F. up nhEF TX" "G1  Raise floor to nhEF (TX)"
+ldt  48 x "-- Animated wall" "--  Animated wall (scrolls horizontally)"
+ldt  49 c "S1 Ceil dn flr+8" "S1  Lower ceiling to floor + 8"
+ldt  50 d "S1 Close door"    "S1  Close door"
+ldt  51 e "S- Secret level"  "S-  End level, go to secret level"
+ldt  52 e "W- End level"     "W-  End level, go to next level"
+ldt  53 m "W1 Start moving"  "W1  Start moving floor"
+ldt  54 m "W1 Stop moving f" "W1  Stop  moving floor"
+ldt  55 F "S1 F. up LIC-8"   "S1  Raise floor to LIC - 8, crush"
+ldt  56 F "W1& F. up LIC-8"  "W1& Raise floor to LIC - 8, crush"
+ldt  57 C "W1& Stop crush"   "W1& Stop  crushing"
+ldt  58 F "W1 Floor up 24"   "W1  Raise floor by 24"
+ldt  59 F "W1 F. up 24 TXP"  "W1  Raise floor by 24 (TXP)"
+ldt  60 f "SR Floor dn LEF"  "SR  Lower floor to LEF"
+ldt  61 d "SR Open door (O)" "SR  Open  door (stays open)"
+ldt  62 l "SR Lower lift"    "SR  Lower lift"
+ldt  63 d "SR Open door"     "SR  Open  door"
+ldt  64 F "SR Floor up LIC"  "SR  Raise floor to LIC"
+ldt  65 F "SR F. up LIC-8"   "SR  Raise floor to LIC - 8, crush"
+ldt  66 F "SR& F. up 24 TX"  "SR& Raise floor by 24 (TX)"
+ldt  67 F "SR& F. up 32 TX"  "SR& Raise floor by 32 (TX)"
+ldt  68 f "SR& F up nhEF TX" "SR& Raise floor to nhEF (TX)"
+ldt  69 F "SR F. up nhEF"    "SR  Raise floor to nhEF"
+ldt  70 f "SR F. DN HEF+8"   "SR  Lower turbo floor to HEF + 8"
+ldt  71 f "S1 F. DN HEF+8"   "S1  Lower turbo floor to HEF + 8"
+ldt  72 c "WR Ceil dn flr+8" "WR  Lower ceiling to floor + 8"
+ldt  73 C "WR& Crush SS"     "WR& Start slow crushing, slow hurt"
+ldt  74 C "WR& Stop crush"   "WR& Stop  crushing"
+ldt  75 d "WR Close door"    "WR  Close door"
+ldt  76 d "WR Close for 30s" "WR  Close door for 30 seconds"
+ldt  77 C "WR& Crush FF"     "WR& Start fast crushing, fast hurt"
+#ldt 78 x "-- Unimplemented" "--  Unimplemented"
+ldt  79 L "WR Light to 35"   "WR  Light level goes to 35"
+ldt  80 L "WR Light to HE"   "WR  Light level goes to HE"
+ldt  81 L "WR Light to 255"  "WR  Light level goes to 255"
+ldt  82 f "WR Floor dn LEF"  "WR  Lower floor to LEF"
+ldt  83 f "WR Floor dn HEF"  "WR  Lower floor to HEF"
+ldt  84 f "WR F. dn LEF NXP" "WR  Lower floor to LEF (NXP)"
+#ldt 85 x "-- Unimplemented" "--  Unimplemented"
+ldt  86 d "WR Open door (O)" "WR  Open  door (stays open)"
+ldt  87 m "WR& Start moving" "WR& Start moving floor"
+ldt  88 l "WR Lower lift"    "WR  Lower lift"
+ldt  89 m "WR& Stop moving"  "WR& Stop  moving floor"
+ldt  90 d "WR Open door"     "WR  Open  door"
+ldt  91 F "WR Floor up LIC"  "WR  Raise floor to LIC"
+ldt  92 F "WR Floor up 24"   "WR  Raise floor by 24"
+ldt  93 F "WR F. up 24 TXP"  "WR  Raise floor by 24 (TXP)"
+ldt  94 F "WR F. up LIC-8"   "WR  Raise floor to LIC - 8, crush"
+ldt  95 F "WR F. up nhEF TX" "WR  Raise floor to nhEF (TX)"
+ldt  96 F "WR Floor up SLT"  "WR  Raise floor by ShortestLowerTexture"
+ldt  97 t "WR Teleport"      "WR  Teleport to another sector"
+ldt  98 f "WR F. DN HEF+8"   "WR  Lower turbo floor to HEF + 8"
+ldt  99 b "SR OPEN blu door" "SR  Open  turbo door, blue key [v1.6]"
+ldt 100 s "W1 RaiseStairs16" "W1  Raise stairs (step=16), crush [v1.6]"
+ldt 101 F "S1 Floor up LIC"  "S1  Raise floor to LIC"
+ldt 102 f "S1 Floor dn HEF"  "S1  Lower floor to HEF"
+ldt 103 d "S1 Open door (O)" "S1  Open  door (stays open)"
+ldt 104 L "W1 Light to LE"   "W1  Light level goes to LE"
+ldt 105 D "WR OPEN door"     "WR  Open  turbo door [v1.6]"
+ldt 106 D "WR OPEN door (O)" "WR  Open  turbo door (stays open) [v1.6]"
+ldt 107 D "WR CLOSE door"    "WR  Close turbo door [v1.6]"
+ldt 108 D "W1 OPEN door"     "W1  Open  turbo door [v1.6]"
+ldt 109 D "W1 OPEN door (O)" "W1  Open  turbo door (stays open) [v1.6]"
+ldt 110 D "W1 CLOSE door"    "W1  Close turbo door [v1.6]"
+ldt 111 D "S1 OPEN door"     "S1  Open  turbo door [v1.6]"
+ldt 112 D "S1 OPEN door (O)" "S1  Open  turbo door (stays open) [v1.6]"
+ldt 113 D "S1 CLOSE door"    "S1  Close turbo door [v1.6]"
+ldt 114 D "SR OPEN door"     "SR  Open  turbo door [v1.6]"
+ldt 115 D "SR OPEN door (O)" "SR  Open  turbo door (stays open) [v1.6]"
+ldt 116 D "SR CLOSE door"    "SR  Close turbo door [v1.6]"
+ldt 117 D "DR OPEN door"     "DR  Open  turbo door [v1.6]"
+ldt 118 D "D1 OPEN door (O)" "D1  Open  turbo door (stays open) [v1.6]"
+ldt 119 F "W1 Floor up nhEF" "W1  Raise floor to nhEF [v1.6]"
+ldt 120 l "WR LOWER lift"    "WR  Lower turbo lift [v1.6]"
+ldt 121 l "W1 LOWER lift"    "W1  Lower turbo lift [v1.6]"
+ldt 122 l "S1 LOWER lift"    "S1  Lower turbo lift [v1.6]"
+ldt 123 l "SR LOWER lift"    "SR  Lower turbo lift [v1.6]"
+ldt 124 e "W- Secret level"  "W-  End level, go to secret level [v1.6]"
+ldt 125 t "W1 Teleport mons" "W1  Teleport monsters only [v1.6]"
+ldt 126 t "WR Teleport mons" "WR  Teleport monsters only [v1.6]"
+ldt 127 s "S1 RaiseStairs16" "S1  Raise stairs (step=16), crush [v1.6]"
+ldt 128 F "WR Floor up nhEF" "WR  Raise floor to nhEF [v1.6]"
+ldt 129 F "WR Floor UP nhEF" "WR  Raise turbo floor to nhEF [v1.6]"
+ldt 130 F "W1 Floor UP nhEF" "W1  Raise turbo floor to nhEF [v1.6]"
+ldt 131 F "S1 Floor UP nhEF" "S1  Raise turbo floor to nhEF [v1.6]"
+ldt 132 F "SR Floor UP nhEF" "SR  Raise turbo floor to nhEF [v1.6]"
+ldt 133 b "S1 OPEN blu door" "S1  Open  turbo door, blue key [v1.6]"
+ldt 134 r "SR OPEN red door" "SR  Open  turbo door, red key [v1.6]"
+ldt 135 r "S1 OPEN red door" "S1  Open  turbo door, red key [v1.6]"
+ldt 136 y "SR OPEN yel door" "SR  Open  turbo door, yellow key [v1.6]"
+ldt 137 y "S1 OPEN yel door" "S1  Open  turbo door, yellow key [v1.6]"
+ldt 138 L "SR Light to 255"  "SR  Light level goes to 255 [v1.6]"
+ldt 139 L "SR Light to 0"    "SR  Light level goes to 0 [v1.6]"
+ldt 140 F "S1 Floor up 512"  "S1  Raise floor by 512, medium speed [v1.6]"
+ldt 141 C "W1& Crush SS sil" "W1& Start slow crushing, slow hurt, silent [v1.6]"
+ldt 271 x "-- Xfer sky"      "--  Xfer straight upper to sky tex. [MBF]"
+ldt 272 x "-- Xfer mir. sky" "--  Xfer mirrored upper to sky tex. [MBF]"
+
+#
+#	Definition of sector types
+#	Format is : st <number> <shortdesc> <longdesc>
+#	<shortdesc> must not exceed 14 characters.
+#
+
+st  0 "X Normal"       "X Normal"
+st  1 "  Blinks rand"  "  Light blinks randomly"
+st  2 "  Flashes 2 Hz" "  Light flashes 2 Hz"
+st  3 "  Flashes 1 Hz" "  Light flashes 1 Hz"
+st  4 "P -20% & 2Hz"   "P -10/20% health, flashes 2 Hz"
+st  5 "P -10% health"  "P -5/10% health"
+st  7 "P -5% health"   "P -2/5% health"
+st  8 "  Oscillates"   "  Light oscillates"
+st  9 "P Secret"       "P Secret"
+st 10 "  Closes 30 s"  "  30 s after level start, ceiling closes like a door"
+st 11 "P -20% & end"   "P -10/20% health and end level when health <= 10%"
+st 12 "  Flash1Hz syn" "  Light flashes 1 Hz, synchronized"
+st 13 "  Flash2Hz syn" "  Light flashes 2 Hz, synchronized"
+st 14 "  Opens 300 s"  "  300 s after level start, ceiling opens like a door"
+st 16 "P -20% health"  "P -10/20% health"
+st 17 "  Flicker rand" "  Light flickers on and off randomly [v1.6]"
+
+#
+#	Definition of thing groups
+#	Format is : thinggroup <thinggroup> <colour> <description>
+#
+
+thinggroup p rgb:4/f/4 "Player"
+thinggroup m rgb:f/0/0 "Monster"
+thinggroup w rgb:f/a/0 "Weapon"
+thinggroup a rgb:8/5/0 "Ammunition"
+thinggroup h rgb:2/8/0 "Health & armour"
+thinggroup b rgb:2/8/0 "Misc. bonus"
+thinggroup k rgb:f/0/f "Key"
+thinggroup d rgb:6/6/c "Misc. decoration"
+thinggroup l rgb:6/6/c "Light source"
+thinggroup g rgb:6/6/c "Gory decoration"
+thinggroup c rgb:6/6/c "Corpse"
+thinggroup s rgb:0/b/d "Special"
+
+#
+#	Definition of things
+#	Format is :
+#	thing <number> <thinggroup> <flags> <radius> <desc> [<sprite>]
+#	<desc> must not exceed 19 characters.
+#
+
+# FIXME
+#   10 wrong sprite, perhaps wrong description (E1M1)
+# 2020 missing (E1M2)
+# 2021 missing (E1M2)
+# 2024 wrong sprite, perhaps wrong description (E1M5)
+# 2027 missing (E1M3)
+# 2032 missing (E1M11)
+# 2036 missing (E1M1)
+# 2037 missing (E1M3)
+
+thing 2007 a -  20 "Clip"			CLIP
+thing 2048 a -  20 "Box of bullets"		AMMO
+thing 2008 a -  20 "4 shotgun shells"		SHEL
+thing 2049 a -  20 "Box shotgun shells"		SBOX
+thing 2010 a -  20 "Rocket"			ROCK
+thing 2046 a -  20 "Box of rockets"		BROK
+thing 2047 a -  20 "Energy cell"		CELL
+thing   17 a -  20 "Energy cell pack"		CELP
+thing    8 a -  20 "Backpack full ammo"		BPAK
+
+thing 2025 b -  20 "Rad. shielding suit"	SUIT
+thing 2026 b -  20 "Computer area map"		PMAP
+thing 2024 b -  20 "Partial invis."		PINS
+thing 2023 b -  20 "Berserk"			PSTR
+thing 2022 b -  20 "Invulnerability"		PINV
+thing 2045 b -  20 "Light amp. visor"		PVIS
+thing 2016 b -  16 "Evil sceptre"		BON3
+thing 2017 b -  16 "Unholy bible"		BON4
+
+thing   15 c -  16 "Dead player (green)"	PLAYN
+thing   18 c -  20 "Dead trooper"		POSSL
+thing   19 c -  20 "Dead sergeant"		SPOSL
+thing   20 c -  20 "Dead imp"			TROOM
+thing   21 c -  16 "Dead demon"			SARGN
+thing   22 c -  16 "Dead cacodemon"		HEADL
+thing   23 c -  16 "Dead lost soul"		SKULK
+
+thing 2035 d -  10 "Barrel"			BAR1
+thing   48 d -  16 "Technical column"		ELEC
+thing   30 d -  16 "Tall green pillar"		COL1
+thing   32 d -  16 "Tall red pillar"		COL3
+thing   31 d -  16 "Short green pillar"		COL2
+thing   33 d -  16 "Short red pillar"		COL4
+thing   36 d -  16 "Pillar w/heart"		COL5
+thing   37 d -  16 "Red pillar w/skull"		COL6
+thing   41 d -  16 "Evil eye"			CEYE
+thing   42 g -  16 "Floating skulls"		FSKU
+thing   43 d -  16 "Grey tree"			TRE1
+thing   47 d -  16 "Brown stub"			SMIT
+thing   54 d -  32 "Tall brown tree"		TRE2
+
+thing   10 g -  16 "Mushed player"		PLAYW
+thing   12 g -  16 "Mushed player 2"		PLAYW
+thing   24 g -  16 "Pool of blood"		POL5
+thing   27 g -  16 "Pole with skull"		POL4
+thing   28 g -  16 "Skewer with heads"		POL2
+thing   29 g -  16 "Pile of skulls"		POL3
+thing   25 g -  16 "Impaled body"		POL1
+thing   26 g -  16 "Impaled twitching"		POL6
+thing   49 g -  16 "Swaying body O"		GOR1
+thing   63 g -  16 "Swaying body"		GOR1
+thing   50 g -  16 "Hanging arms out O"		GOR2
+thing   59 g -  16 "Hanging arms out"		GOR2
+thing   53 g -  16 "Hanging leg O"		GOR5
+thing   62 g -  16 "Hanging leg"		GOR5
+thing   51 g -  16 "Hanging one-legged O"	GOR3	# FIXME cut off
+thing   61 g -  16 "Hanging one-legged"		GOR3
+thing   52 g -  16 "Hanging torso O"		GOR4
+thing   60 g -  16 "Hanging torso"		GOR4
+
+thing 2014 h -  20 "Health bonus"		BON1
+thing 2011 h -  20 "Stimpack"			STIM
+thing 2012 h -  20 "Medikit"			MEDI
+thing 2013 h -  20 "Supercharge"		SOUL
+thing 2015 h -  20 "Armor bonus"		BON2
+thing 2018 h -  20 "Armor"			ARM1
+thing 2019 h -  20 "Megaarmor"			ARM2
+
+thing    5 k -  20 "Blue key"			GKEY
+thing    6 k -  20 "Yellow key"			SKEY
+thing    7 k -  20 "Red key"			BKEY
+thing   40 k -  20 "Blue skull key"		BSKU
+thing   39 k -  20 "Yellow skull key"		YSKU
+thing   38 k -  20 "Red skull key"		RSKU
+
+thing 2028 l -  16 "Lamp"			COLU
+thing   34 l -  16 "Candle"			CAND
+thing   35 l -  16 "Candelabra"			CBRA
+thing   44 l -  16 "Tall blue torch"		TBLU
+thing   45 l -  16 "Tall green torch"		TGRN
+thing   46 l -  16 "Tall red torch"		TRED
+thing   55 l -  16 "Short blue torch"		SMBT
+thing   56 l -  16 "Short green torch"		SMGT
+thing   57 l -  16 "Short red torch"		SMRT
+
+thing 3004 m -  20 "Trooper"			POSS
+thing    9 m -  20 "Sergeant"			SPOS
+thing 3001 m -  20 "Imp"			TROO
+thing 3002 m -  30 "Demon"			SARG
+thing 3003 m -  24 "Baron of hell"		BOSS
+thing   58 m s  30 "Spectre"			SARG
+thing 3006 m -  16 "Lost soul"			SKUL
+thing 3005 m -  31 "Cacodemon"			HEAD
+thing    7 m - 128 "Spider mastermind"		SPID
+thing   16 m -  40 "Cyberdemon"			CYBR
+
+thing    1 p -  16 "Player 1 start"		PLAY
+thing    2 p -  16 "Player 2 start"		PLAY
+thing    3 p -  16 "Player 3 start"		PLAY
+thing    4 p -  16 "Player 4 start"		PLAY
+thing  888 p -  12 "Dog [MBF]"
+thing   11 p -  16 "Deathmatch start"		PLAYF1
+thing   14 p -  16 "Teleport exit"		TFOG
+
+thing 2005 w -  20 "Chainsaw"			CSAW
+thing 2001 w -  20 "Shotgun"			SHOT
+thing 2002 w -  20 "Chaingun"			MGUN
+thing 2003 w -  20 "Rocket launcher"		LAUN
+thing 2004 w -  20 "Plasma gun"			PLAS
+thing 2006 w -  20 "BFG9000"			BFUG
+
+thing 5001 s -  20 "Point pusher [Boom]"
+thing 5002 s -  20 "Point puller [Boom]"
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ygd/doom2.ygd	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,555 @@
+# Yadex game definition file version 4
+#
+#	doom2.ygd
+#	Yadex Game Definitions for Doom II and Final Doom
+#	See doc/ygd.html for the specs.
+#	AYM 1998-01-03
+#
+
+# EDGE stuff courtesy of Andrew Apted. Mistakes courtesy of AYM.
+# Boom stuff courtesy of Andrew Apted, 2000-09-20.
+
+level_format    doom
+level_name      map01
+picture_format  normal
+sky_flat        f_sky1
+texture_format  normal
+texture_lumps   normal
+
+#
+#	Definition of linedef type groups
+#	Format is : ldtgroup <ldtgroup> <description>
+#
+
+ldtgroup d "Door"
+ldtgroup r "Door (red key)"
+ldtgroup y "Door (yellow key)"
+ldtgroup b "Door (blue key)"
+ldtgroup D "Door (turbo)"
+ldtgroup l "Lift"
+ldtgroup v "Elevator"
+ldtgroup F "Floor (raise)"
+ldtgroup f "Floor (lower)"
+ldtgroup c "Ceiling"
+ldtgroup C "Crushing ceiling"
+ldtgroup t "Teleport"
+ldtgroup L "Light"
+ldtgroup e "End level"
+ldtgroup m "Moving floor"
+ldtgroup s "Raising stairs"
+ldtgroup A "Animated"
+ldtgroup E "Extrafloor"
+ldtgroup x "Misc."
+
+#
+#	Definition of linedef types
+#	Format is : ldt <number> <ldtgroup> <shortdesc> <longdesc>
+#	<shortdesc> must not exceed 16 characters.
+#
+
+ldt   0 x "-- Normal"        "--  Normal"
+ldt   1 d "DR Open door"     "DR  Open  door"
+ldt   2 d "W1 Open door (O)" "W1  Open  door (stays open)"
+ldt   3 d "W1 Close door"    "W1  Close door"
+ldt   4 d "W1 Open door"     "W1  Open  door"
+ldt   5 F "W1 Floor up LIC"  "W1  Raise floor to LIC"
+ldt   6 C "W1 Crush FF"      "W1  Start fast crushing, fast hurt"
+ldt   7 s "S1 Raise stairs"  "S1  Raise stairs (several sectors 0/999)"
+ldt   8 s "W1 Raise stairs"  "W1  Raise stairs (several sectors 0/999)"
+ldt   9 x "S1 Donut"         "S1  Lower floor, raise Ne. floor (NXP) 'Donut'"
+ldt  10 l "W1 Lower lift"    "W1  Lower lift"
+ldt  11 e "S- End level"     "S-  End level, go to next level"
+ldt  12 L "W1 Light to HE"   "W1  Light level goes to HE"
+ldt  13 L "W1 Light to 255"  "W1  Light level goes to 255"
+ldt  14 F "S1& F. up 32 TX"  "S1& Raise floor by 32 (TX)"
+ldt  15 F "S1& F. up 24 TX"  "S1& Raise floor by 24 (TX)"
+ldt  16 d "W1 Close for 30s" "W1  Close door for 30 seconds"
+ldt  17 L "W1 Start blink"   "W1  Start blinking lights"
+ldt  18 F "S1 Floor up nhEF" "S1  Raise floor to nhEF"
+ldt  19 f "W1 Floor dn HEF"  "W1  Lower floor to HEF"
+ldt  20 F "S1& F up nhEF TX" "S1& Raise floor to nhEF (TX)"
+ldt  21 l "S1 Lower lift"    "S1  Lower lift"
+ldt  22 F "W1& F up nhEF TX" "W1& Raise floor to nhEF (TX)"
+ldt  23 f "S1 Floor dn LEF"  "S1  Lower floor to LEF"
+ldt  24 F "G1 Floor up LIC"  "G1  Raise floor to LIC"
+ldt  25 C "W1 Crush FS"      "W1  Start fast crushing, slow hurt"
+ldt  26 b "DR Open blue dr"  "DR  Open  door, blue key"
+ldt  27 y "DR Open yel dr"   "DR  Open  door, yellow key"
+ldt  28 r "DR Open red dr"   "DR  Open  door, red key"
+ldt  29 d "S1 Open door"     "S1  Open  door"
+ldt  30 F "W1 Floor up SLT"  "W1  Raise floor by ShortestLowerTexture"
+ldt  31 d "D1 Open door (O)" "D1  Open  door (stays open)"
+ldt  32 b "D1 Open blu (O)"  "D1  Open  door (stays open), blue key"
+ldt  33 r "D1 Open red (O)"  "D1  Open  door (stays open), red key"
+ldt  34 y "D1 Open yel (O)"  "D1  Open  door (stays open), yellow key"
+ldt  35 L "W1 Light to 35"   "W1  Light level goes to 35"
+ldt  36 f "W1 F. DN HEF+8"   "W1  Lower turbo floor to HEF + 8"
+ldt  37 f "W1 F. dn LEF NXP" "W1  Lower floor to LEF (NXP)"
+ldt  38 f "W1 Floor dn LEF"  "W1  Lower floor to LEF"
+ldt  39 t "W1 Teleport"      "W1  Teleport to another sector"
+ldt  40 c "W1 Ceil up HEC"   "W1  Raise ceiling to HEC"
+ldt  41 c "S1 Ceil dn floor" "S1  Lower ceiling to floor"
+ldt  42 d "SR Close door"    "SR  Close door"
+ldt  43 c "SR Ceil dn floor" "SR  Lower ceiling to floor"
+ldt  44 c "W1 Ceil dn flr+8" "W1  Lower ceiling to floor + 8"
+ldt  45 f "SR Floor dn HEF"  "SR  Lower floor to HEF"
+ldt  46 d "GR Open door (O)" "GR  Open  door (stays open)"
+ldt  47 F "G1 F. up nhEF TX" "G1  Raise floor to nhEF (TX)"
+ldt  48 A "-- Scroll left"   "--  Scrolling wall, left"
+ldt  49 c "S1 Ceil dn flr+8" "S1  Lower ceiling to floor + 8"
+ldt  50 d "S1 Close door"    "S1  Close door"
+ldt  51 e "S- Secret level"  "S-  End level, go to secret level"
+ldt  52 e "W- End level"     "W-  End level, go to next level"
+ldt  53 m "W1 Start moving"  "W1  Start moving floor"
+ldt  54 m "W1 Stop moving f" "W1  Stop  moving floor"
+ldt  55 F "S1 F. up LIC-8"   "S1  Raise floor to LIC - 8, crush"
+ldt  56 F "W1& F. up LIC-8"  "W1& Raise floor to LIC - 8, crush"
+ldt  57 C "W1& Stop crush"   "W1& Stop  crushing"
+ldt  58 F "W1 Floor up 24"   "W1  Raise floor by 24"
+ldt  59 F "W1 F. up 24 TXP"  "W1  Raise floor by 24 (TXP)"
+ldt  60 f "SR Floor dn LEF"  "SR  Lower floor to LEF"
+ldt  61 d "SR Open door (O)" "SR  Open  door (stays open)"
+ldt  62 l "SR Lower lift"    "SR  Lower lift"
+ldt  63 d "SR Open door"     "SR  Open  door"
+ldt  64 F "SR Floor up LIC"  "SR  Raise floor to LIC"
+ldt  65 F "SR F. up LIC-8"   "SR  Raise floor to LIC - 8, crush"
+ldt  66 F "SR& F. up 24 TX"  "SR& Raise floor by 24 (TX)"
+ldt  67 F "SR& F. up 32 TX"  "SR& Raise floor by 32 (TX)"
+ldt  68 f "SR& F up nhEF TX" "SR& Raise floor to nhEF (TX)"
+ldt  69 F "SR F. up nhEF"    "SR  Raise floor to nhEF"
+ldt  70 f "SR F. DN HEF+8"   "SR  Lower turbo floor to HEF + 8"
+ldt  71 f "S1 F. DN HEF+8"   "S1  Lower turbo floor to HEF + 8"
+ldt  72 c "WR Ceil dn flr+8" "WR  Lower ceiling to floor + 8"
+ldt  73 C "WR& Crush SS"     "WR& Start slow crushing, slow hurt"
+ldt  74 C "WR& Stop crush"   "WR& Stop  crushing"
+ldt  75 d "WR Close door"    "WR  Close door"
+ldt  76 d "WR Close for 30s" "WR  Close door for 30 seconds"
+ldt  77 C "WR& Crush FF"     "WR& Start fast crushing, fast hurt"
+
+ldt  78 x "SR Floor -- NXP"  "SR  Floor transfer (NXP) [Boom]"
+
+ldt  79 L "WR Light to 35"   "WR  Light level goes to 35"
+ldt  80 L "WR Light to HE"   "WR  Light level goes to HE"
+ldt  81 L "WR Light to 255"  "WR  Light level goes to 255"
+ldt  82 f "WR Floor dn LEF"  "WR  Lower floor to LEF"
+ldt  83 f "WR Floor dn HEF"  "WR  Lower floor to HEF"
+ldt  84 f "WR F. dn LEF NXP" "WR  Lower floor to LEF (NXP)"
+
+ldt  85 A "-- Scroll right"  "--  Scrolling wall, right [Boom]"
+
+ldt  86 d "WR Open door (O)" "WR  Open  door (stays open)"
+ldt  87 m "WR& Start moving" "WR& Start moving floor"
+ldt  88 l "WR Lower lift"    "WR  Lower lift"
+ldt  89 m "WR& Stop moving"  "WR& Stop  moving floor"
+ldt  90 d "WR Open door"     "WR  Open  door"
+ldt  91 F "WR Floor up LIC"  "WR  Raise floor to LIC"
+ldt  92 F "WR Floor up 24"   "WR  Raise floor by 24"
+ldt  93 F "WR F. up 24 TXP"  "WR  Raise floor by 24 (TXP)"
+ldt  94 F "WR F. up LIC-8"   "WR  Raise floor to LIC - 8, crush"
+ldt  95 F "WR F. up nhEF TX" "WR  Raise floor to nhEF (TX)"
+ldt  96 F "WR Floor up SLT"  "WR  Raise floor by ShortestLowerTexture"
+ldt  97 t "WR Teleport"      "WR  Teleport to another sector"
+ldt  98 f "WR F. DN HEF+8"   "WR  Lower turbo floor to HEF + 8"
+ldt  99 b "SR OPEN blu door" "SR  Open  turbo door, blue key [v1.6]"
+ldt 100 s "W1 RaiseStairs16" "W1  Raise stairs (step=16), crush [v1.6]"
+ldt 101 F "S1 Floor up LIC"  "S1  Raise floor to LIC"
+ldt 102 f "S1 Floor dn HEF"  "S1  Lower floor to HEF"
+ldt 103 d "S1 Open door (O)" "S1  Open  door (stays open)"
+ldt 104 L "W1 Light to LE"   "W1  Light level goes to LE"
+ldt 105 D "WR OPEN door"     "WR  Open  turbo door [v1.6]"
+ldt 106 D "WR OPEN door (O)" "WR  Open  turbo door (stays open) [v1.6]"
+ldt 107 D "WR CLOSE door"    "WR  Close turbo door [v1.6]"
+ldt 108 D "W1 OPEN door"     "W1  Open  turbo door [v1.6]"
+ldt 109 D "W1 OPEN door (O)" "W1  Open  turbo door (stays open) [v1.6]"
+ldt 110 D "W1 CLOSE door"    "W1  Close turbo door [v1.6]"
+ldt 111 D "S1 OPEN door"     "S1  Open  turbo door [v1.6]"
+ldt 112 D "S1 OPEN door (O)" "S1  Open  turbo door (stays open) [v1.6]"
+ldt 113 D "S1 CLOSE door"    "S1  Close turbo door [v1.6]"
+ldt 114 D "SR OPEN door"     "SR  Open  turbo door [v1.6]"
+ldt 115 D "SR OPEN door (O)" "SR  Open  turbo door (stays open) [v1.6]"
+ldt 116 D "SR CLOSE door"    "SR  Close turbo door [v1.6]"
+ldt 117 D "DR OPEN door"     "DR  Open  turbo door [v1.6]"
+ldt 118 D "D1 OPEN door (O)" "D1  Open  turbo door (stays open) [v1.6]"
+ldt 119 F "W1 Floor up nhEF" "W1  Raise floor to nhEF [v1.6]"
+ldt 120 l "WR LOWER lift"    "WR  Lower turbo lift [v1.6]"
+ldt 121 l "W1 LOWER lift"    "W1  Lower turbo lift [v1.6]"
+ldt 122 l "S1 LOWER lift"    "S1  Lower turbo lift [v1.6]"
+ldt 123 l "SR LOWER lift"    "SR  Lower turbo lift [v1.6]"
+ldt 124 e "W- Secret level"  "W-  End level, go to secret level [v1.6]"
+ldt 125 t "W1 Teleport mons" "W1  Teleport monsters only [v1.6]"
+ldt 126 t "WR Teleport mons" "WR  Teleport monsters only [v1.6]"
+ldt 127 s "S1 RaiseStairs16" "S1  Raise stairs (step=16), crush [v1.6]"
+ldt 128 F "WR Floor up nhEF" "WR  Raise floor to nhEF [v1.6]"
+ldt 129 F "WR Floor UP nhEF" "WR  Raise turbo floor to nhEF [v1.6]"
+ldt 130 F "W1 Floor UP nhEF" "W1  Raise turbo floor to nhEF [v1.6]"
+ldt 131 F "S1 Floor UP nhEF" "S1  Raise turbo floor to nhEF [v1.6]"
+ldt 132 F "SR Floor UP nhEF" "SR  Raise turbo floor to nhEF [v1.6]"
+ldt 133 b "S1 OPEN blu door" "S1  Open  turbo door, blue key [v1.6]"
+ldt 134 r "SR OPEN red door" "SR  Open  turbo door, red key [v1.6]"
+ldt 135 r "S1 OPEN red door" "S1  Open  turbo door, red key [v1.6]"
+ldt 136 y "SR OPEN yel door" "SR  Open  turbo door, yellow key [v1.6]"
+ldt 137 y "S1 OPEN yel door" "S1  Open  turbo door, yellow key [v1.6]"
+ldt 138 L "SR Light to 255"  "SR  Light level goes to 255 [v1.6]"
+ldt 139 L "SR Light to 0"    "SR  Light level goes to 0 [v1.6]"
+ldt 140 F "S1 Floor up 512"  "S1  Raise floor by 512, medium speed [v1.6]"
+ldt 141 C "W1& Crush SS sil" "W1& Start slow crushing, slow hurt, silent [v1.6]"
+
+ldt 142 F "W1 Floor up 512"  "W1  Raise floor by 512 [Boom]"
+ldt 143 l "W1& F. up 24 TX"  "W1& Raise floor by 24 (TX) [Boom]"
+ldt 144 l "W1& F. up 32 TX"  "W1& Raise floor by 32 (TX) [Boom]"
+ldt 145 c "W1 Ceil dn floor" "W1  Lower ceiling to floor [Boom]"
+ldt 146 x "W1 Donut"         "W1  Lower floor, raise NE floor (NXP) [Boom]"
+ldt 147 F "WR Floor up 512"  "WR  Raise floor by 512 [Boom]"
+ldt 148 l "WR& F. up 24 TX"  "WR& Raise floor by 24 (TX) [Boom]"
+ldt 149 l "WR& F. up 32 TX"  "WR& Raise floor by 32 (TX) [Boom]"
+ldt 150 C "WR& Crush SS sil" "WR& Start slow crushing, silent [Boom]"
+ldt 151 c "WR Ceil up HEC"   "WR  Raise ceiling to HEC [Boom]"
+ldt 152 c "WR Ceil dn floor" "WR  Lower ceiling to floor [Boom]"
+ldt 153 x "W1 Floor -- TXP"  "W1  Floor transfer (TXP) [Boom]"
+ldt 154 x "WR Floor -- TXP"  "WR  Floor transfer (TXP) [Boom]"
+ldt 155 x "WR Donut"         "WR  Lower floor, raise NE floor (NXP) [Boom]"
+ldt 156 L "WR Start blink"   "WR  Start blinking lights [Boom]"
+ldt 157 L "WR Light to LE"   "WR  Light level goes to LE [Boom]"
+ldt 158 F "S1 Floor up SLT"  "S1  Raise floor by ShortestLowerTex [Boom]"
+ldt 159 f "S1 F. dn LEF NX"  "S1  Lower floor to LEF (NXP) [Boom]"
+ldt 160 F "S1 F. up 24 TXP"  "S1  Raise floor by 24 (TXP) [Boom]"
+ldt 161 F "S1 Floor up 24"   "S1  Raise floor by 24 [Boom]"
+ldt 162 m "S1 Start moving"  "S1  Start moving floor [Boom]"
+ldt 163 m "S1 Stop moving f" "S1  Stop  moving floor [Boom]"
+ldt 164 C "S1 Crush FF"      "S1  Start fast crushing [Boom]"
+ldt 165 C "S1& Crush SS sil" "S1& Start slow crushing, silent [Boom]"
+ldt 166 c "S1 Ceil up HEC"   "S1  Raise ceiling to HEC [Boom]"
+ldt 167 c "S1 Ceil dn flr+8" "S1  Lower ceiling to floor + 8 [Boom]"
+ldt 168 C "S1& Stop crush"   "S1& Stop  crushing [Boom]"
+ldt 169 L "S1 Light to HE"   "S1  Light level goes to HE [Boom]"
+ldt 170 L "S1 Light to 0"    "S1  Light level goes to 0 [Boom]"
+ldt 171 L "S1 Light to 255"  "S1  Light level goes to 255 [Boom]"
+ldt 172 L "S1 Start blink"   "S1  Start blinking lights [Boom]"
+ldt 173 L "S1 Light to LE"   "S1  Light level goes to LE [Boom]"
+ldt 174 t "S1 Teleport"      "S1  Teleport to another sector [Boom]"
+ldt 175 d "S1 Close for 30s" "S1  Close door for 30 seconds [Boom]"
+ldt 176 F "SR Floor up SLT"  "SR  Raise floor by ShortestLowerTex [Boom]"
+ldt 177 f "SR F. dn LEF NX"  "SR  Lower floor to LEF (NXP) [Boom]"
+ldt 178 F "SR Floor up 512"  "SR  Raise floor by 512 [Boom]"
+ldt 179 F "SR F. up 24 TXP"  "SR  Raise floor by 24 (TXP) [Boom]"
+ldt 180 F "SR Floor up 24"   "SR  Raise floor by 24 [Boom]"
+ldt 181 m "SR Start moving"  "SR  Start moving floor [Boom]"
+ldt 182 m "SR Stop moving f" "SR  Stop  moving floor [Boom]"
+ldt 183 C "SR Crush FF"      "SR  Start fast crushing [Boom]"
+ldt 184 C "SR& Crush SS"     "SR& Start slow crushing [Boom]"
+ldt 185 C "SR& Crush SS sil" "SR& Start slow crushing, silent [Boom]"
+ldt 186 c "SR Ceil up HEC"   "SR  Raise ceiling to HEC [Boom]"
+ldt 187 c "SR Ceil dn flr+8" "SR  Lower ceiling to floor + 8 [Boom]"
+ldt 188 C "SR& Stop crush"   "SR& Stop  crushing [Boom]"
+ldt 189 x "S1 Floor -- TXP"  "S1  Floor transfer (TXP) [Boom]"
+ldt 190 x "SR Floor -- TXP"  "SR  Floor transfer (TXP) [Boom]"
+ldt 191 x "SR Donut"         "SR  Lower floor, raise NE floor (NXP) [Boom]"
+ldt 192 L "SR Light to HE"   "SR  Light level goes to HE [Boom]"
+ldt 193 L "SR Start blink"   "SR  Start blinking lights [Boom]"
+ldt 194 L "SR Light to LE"   "SR  Light level goes to LE [Boom]"
+ldt 195 t "SR Teleport"      "SR  Teleport to another sector [Boom]"
+ldt 196 d "SR Close for 30s" "SR  Close door for 30 seconds [Boom]"
+ldt 197 e "G- End level"     "G-  End level, go to next level [Boom]"
+ldt 198 e "G- End level"     "G-  End level, go to secret level [Boom]"
+ldt 199 c "W1 Ceil dn LEC"   "W1  Lower ceiling to LEC [Boom]"
+ldt 200 c "W1 Ceil dn HEF"   "W1  Lower ceiling to HEF [Boom]"
+ldt 201 c "WR Ceil dn LEC"   "WR  Lower ceiling to LEC [Boom]"
+ldt 202 c "WR Ceil dn HEF"   "WR  Lower ceiling to HEF [Boom]"
+ldt 203 c "S1 Ceil dn LEC"   "S1  Lower ceiling to LEC [Boom]"
+ldt 204 c "S1 Ceil dn HEF"   "S1  Lower ceiling to HEF [Boom]"
+ldt 205 c "SR Ceil dn LEC"   "SR  Lower ceiling to LEC [Boom]"
+ldt 206 c "SR Ceil dn HEF"   "SR  Lower ceiling to HEF [Boom]"
+ldt 207 t "W1 Teleport pres" "W1  Teleport preserving dir [Boom]"
+ldt 208 t "WR Teleport pres" "WR  Teleport preserving dir [Boom]"
+ldt 209 t "S1 Teleport pres" "S1  Teleport preserving dir [Boom]"
+ldt 210 t "SR Teleport pres" "SR  Teleport preserving dir [Boom]"
+ldt 211 m "SR Floor toggle"  "SR  Floor toggle to ceil [Boom]"
+ldt 212 m "WR Floor toggle"  "WR  Floor toggle to ceil [Boom]"
+ldt 213 L "-- Xfer F. light" "--  Transfer floor lighting [Boom]"
+ldt 214 A "-- Scrl C. accel" "--  Scroll ceiling with accel [Boom]"
+ldt 215 A "-- Scrl F. accel" "--  Scroll floor with accel [Boom]"
+ldt 216 A "-- Push F. accel" "--  Push objects with accel [Boom]"
+ldt 217 A "-- Sc/Pu F. accl" "--  Scroll & push with accel [Boom]"
+ldt 218 A "-- Scrl wall acc" "--  Scroll wall with accel [Boom]"
+ldt 219 f "W1 F. dn nlEF"    "W1  Lower floor to nlEF [Boom]"
+ldt 220 f "WR F. dn nlEF"    "WR  Lower floor to nlEF [Boom]"
+ldt 221 f "S1 F. dn nlEF"    "S1  Lower floor to nlEF [Boom]"
+ldt 222 f "SR F. dn nlEF"    "SR  Lower floor to nlEF [Boom]"
+ldt 223 x "-- Friction"      "--  Set friction in tagged sectors [Boom]"
+ldt 224 x "-- Wind force"    "--  Set wind in tagged sectors [Boom]"
+ldt 225 x "-- Current force" "--  Set current in tagged sectors [Boom]"
+ldt 226 x "-- Point force"   "--  Set point force in sectors [Boom]"
+ldt 227 v "W1 Elevator nhEF" "W1  Raise elevator to nhEF [Boom]"
+ldt 228 v "WR Elevator nhEF" "WR  Raise elevator to nhEF [Boom]"
+ldt 229 v "S1 Elevator nhEF" "S1  Raise elevator to nhEF [Boom]"
+ldt 230 v "SR Elevator nhEF" "SR  Raise elevator to nhEF [Boom]"
+ldt 231 v "W1 Elevator nlEF" "W1  Lower elevator to nlEF [Boom]"
+ldt 232 v "WR Elevator nlEF" "WR  Lower elevator to nlEF [Boom]"
+ldt 233 v "S1 Elevator nlEF" "S1  Lower elevator to nlEF [Boom]"
+ldt 234 v "SR Elevator nlEF" "SR  Lower elevator to nlEF [Boom]"
+ldt 235 v "W1 Elevator curr" "W1  Move elevator to Current [Boom]"
+ldt 236 v "WR Elevator curr" "WR  Move elevator to Current [Boom]"
+ldt 237 v "S1 Elevator curr" "S1  Move elevator to Current [Boom]"
+ldt 238 v "SR Elevator curr" "SR  Move elevator to Current [Boom]"
+ldt 239 x "W1 Floor -- NXP"  "W1  Floor transfer (NXP) [Boom]"
+ldt 240 x "WR Floor -- NXP"  "WR  Floor transfer (NXP) [Boom]"
+ldt 241 x "S1 Floor -- NXP"  "S1  Floor transfer (NXP) [Boom]"
+ldt 242 x "-- Deep water"    "--  Deep water effect [Boom]"
+ldt 243 t "W1 Telept line"   "W1  Teleport to tagged line [Boom]"
+ldt 244 t "WR Telept line"   "WR  Teleport to tagged line [Boom]"
+ldt 245 A "-- Scrl C. disp"  "--  Scroll ceiling by displacement [Boom]"
+ldt 246 A "-- Scrl F. disp"  "--  Scroll floor by displacement [Boom]"
+ldt 247 A "-- Push F. disp"  "--  Push objects by displacement [Boom]"
+ldt 248 A "-- Sc/Pu F. disp" "--  Scroll & push by displacement [Boom]"
+ldt 249 A "-- Scrl wall dis" "--  Scroll wall by displacement [Boom]"
+ldt 250 A "-- Scroll ceil"   "--  Scroll tagged ceiling [Boom]"
+ldt 251 A "-- Scroll floor"  "--  Scroll tagged floor [Boom]"
+ldt 252 A "-- Push on floor" "--  Push objects on tagged floor [Boom]"
+ldt 253 A "-- Scroll,push f" "--  Scroll & push tagged floor [Boom]"
+ldt 254 A "-- Scrl wal with" "--  Scroll tagged wall with F/C [Boom]"
+ldt 255 A "-- Scrl wal side" "--  Scroll wall using sidedef [Boom]"
+ldt 256 s "WR Raise stairs"  "WR  Raise stairs (several sectors) [Boom]"
+ldt 257 s "WR RaiseStairs16" "WR  Raise stairs (step=16), crush [Boom]"
+ldt 258 s "SR Raise stairs"  "SR  Raise stairs (several sectors) [Boom]"
+ldt 259 s "SR RaiseStairs16" "SR  Raise stairs (step=16), crush [Boom]"
+ldt 260 A "-- Translucency"  "--  Make tagged lines translucent [Boom]"
+ldt 261 L "-- Xfer C. light" "--  Transfer ceiling lighting [Boom]"
+ldt 262 t "W1 Telept line R" "W1  Teleport to line, reverse [Boom]"
+ldt 263 t "WR Telept line R" "WR  Teleport to line, reverse [Boom]"
+ldt 264 t "W1 Tpt line mons" "W1  Teleport monsters to line [Boom]"
+ldt 265 t "WR Tpt line mons" "WR  Teleport monsters to line [Boom]"
+ldt 266 t "W1 Tpt L. mons R" "W1  Teleport monsters to line, rev [Boom]"
+ldt 267 t "WR Tpt L. mons R" "WR  Teleport monsters to line, rev [Boom]"
+ldt 268 t "W1 Teleport mons" "W1  Teleport monsters only [Boom]"
+ldt 269 t "WR Teleport mons" "WR  Teleport monsters only [Boom]"
+
+ldt 271 x "-- Xfer sky"      "--  Xfer straight upper to sky tex. [MBF]"
+ldt 272 x "-- Xfer mir. sky" "--  Xfer mirrored upper to sky tex. [MBF]"
+
+ldt 300 x "SR Sliding door"  "SR  Sliding door [XDoom]"
+ldt 320 x "-- Laser barrier" "--  Laser barrier [XDoom]"
+ldt 321 x "SR Laser off mom" "SR  Switch laser barrier off momentarily [XDoom]"
+ldt 322 x "G1 Laser off per" "G1  Switch laser barrier off permanently [XDoom]"
+ldt 330 x "WR Trigger messg" "WR  Trigger communication device message [XDoom]"
+ldt 331 x "W1 Trigger messg" "W1  Trigger communication device message [XDoom]"
+ldt 332 x "S1 Activate tele" "S1  Activate teleporter with message [XDoom]"
+ldt 333 x "S1 Deact. laser"  "S1  Deactivate laser with message [XDoom]"
+ldt 334 x "M1 Trigger messg" "M1  Trigger communication device message [XDoom]"
+ldt 350 d "W1 Silent door O" "W1  Open silent door by player (stays open) [XDoom]"
+ldt 351 d "S1 Silent door O" "S1  Open silent door by player (stays open) [XDoom]"
+ldt 352 d "M1 Silent door O" "M1  Open silent door by monster (stays open) [XDoom]"
+
+ldt 400 E "-- Thick EF"      "--  Thick extrafloor [EDGE]"
+ldt 401 E "-- Thick EF upr"  "--  Thick extrafloor, side upper [EDGE]"
+ldt 402 E "-- Thick EF lwr"  "--  Thick extrafloor, side lower [EDGE]"
+ldt 403 E "-- Liq EF opaque" "--  Liquid extrafloor, opaque [EDGE]"
+ldt 404 E "-- Liquid EF 20%" "--  Liquid extrafloor, 20% translucent [EDGE]"
+ldt 405 E "-- Liquid EF 40%" "--  Liquid extrafloor, 40% translucent [EDGE]"
+ldt 406 E "-- Liquid EF 60%" "--  Liquid extrafloor, 60% translucent [EDGE]"
+ldt 407 E "-- Liquid EF 80%" "--  Liquid extrafloor, 80% translucent [EDGE]"
+ldt 408 E "-- Liq EF invis"  "--  Liquid extrafloor, invisible [EDGE]"
+
+ldt 9000 A "-- Scroll right" "--  Scrolling wall, right [EDGE]"
+ldt 9001 A "-- Scroll up"    "--  Scrolling wall, up [EDGE]"
+ldt 9002 A "-- Scroll down"  "--  Scrolling wall, down [EDGE]"
+ldt 9003 A "-- Scroll L+U"   "--  Scrolling wall, left and up [EDGE]"
+ldt 9004 A "-- Scroll L+D"   "--  Scrolling wall, left and down [EDGE]"
+ldt 9005 A "-- Scroll R+U"   "--  Scrolling wall, right and up [EDGE]"
+ldt 9006 A "-- Scroll R+D"   "--  Scrolling wall, right and down [EDGE]"
+ldt 9097 t "WR Teleport prv" "WR  Teleport, preserving direction [EDGE]"
+
+#
+#	Definition of sector types
+#	Format is : st <number> <shortdesc> <longdesc>
+#	<shortdesc> must not exceed 14 characters.
+#
+
+st  0 "X Normal"       "X Normal"
+st  1 "  Blinks rand"  "  Light blinks randomly"
+st  2 "  Flashes 2 Hz" "  Light flashes 2 Hz"
+st  3 "  Flashes 1 Hz" "  Light flashes 1 Hz"
+st  4 "P -20% & 2Hz"   "P -10/20% health, flashes 2 Hz"
+st  5 "P -10% health"  "P -5/10% health"
+st  7 "P -5% health"   "P -2/5% health"
+st  8 "  Oscillates"   "  Light oscillates"
+st  9 "P Secret"       "P Secret"
+st 10 "  Closes 30 s"  "  30 s after level start, ceiling closes like a door"
+st 11 "P -20% & end"   "P -10/20% health and end level when health <= 10%"
+st 12 "  Flash1Hz syn" "  Light flashes 1 Hz, synchronized"
+st 13 "  Flash2Hz syn" "  Light flashes 2 Hz, synchronized"
+st 14 "  Opens 300 s"  "  300 s after level start, ceiling opens like a door"
+st 16 "P -20% health"  "P -10/20% health"
+st 17 "  Flicker rand" "  Light flickers on and off randomly [v1.6]"
+
+#
+#	Definition of thing groups
+#	Format is : thinggroup <thinggroup> <colour> <description>
+#
+
+thinggroup p rgb:4/f/4 "Player"
+thinggroup m rgb:f/0/0 "Monster"
+thinggroup w rgb:f/a/0 "Weapon"
+thinggroup a rgb:8/5/0 "Ammunition"
+thinggroup h rgb:2/8/0 "Health & armour"
+thinggroup b rgb:2/8/0 "Misc. bonus"
+thinggroup k rgb:f/0/f "Key"
+thinggroup d rgb:6/6/c "Misc. decoration"
+thinggroup l rgb:6/6/c "Light source"
+thinggroup g rgb:6/6/c "Gory decoration"
+thinggroup c rgb:6/6/c "Corpse"
+thinggroup s rgb:0/b/d "Special"
+
+#
+#	Definition of things
+#	Format is :
+#	thing <number> <thinggroup> <flags> <radius> <desc> [<sprite>]
+#	<desc> must not exceed 19 characters.
+#
+
+thing 2007 a -  20 "Clip"			CLIP
+thing 2048 a -  20 "Box of bullets"		AMMO
+thing 2008 a -  20 "4 shotgun shells"		SHEL
+thing 2049 a -  20 "Box shotgun shells"		SBOX
+thing 2010 a -  20 "Rocket"			ROCK
+thing 2046 a -  20 "Box of rockets"		BROK
+thing 2047 a -  20 "Energy cell"		CELL
+thing   17 a -  20 "Energy cell pack"		CELP
+thing    8 a -  20 "Backpack full ammo"		BPAK
+
+thing 2025 b -  20 "Rad. shielding suit"	SUIT
+thing 2026 b -  20 "Computer area map"		PMAP
+thing 2024 b -  20 "Partial invis."		PINS
+thing 2023 b -  20 "Berserk"			PSTR
+thing 2022 b -  20 "Invulnerability"		PINV
+thing 2045 b -  20 "Light amp. visor"		PVIS
+thing 7000 b -  20 "Night vision [EDGE]"	NVSC
+thing 2016 b -  16 "Evil sceptre [PR]"		BON3
+thing 2017 b -  16 "Unholy bible [PR]"		BON4
+
+thing   15 c -  16 "Dead player (green)"	PLAYN
+thing   18 c -  20 "Dead trooper"		POSSL
+thing   19 c -  20 "Dead sergeant"		SPOSL
+thing   20 c -  20 "Dead imp"			TROOM
+thing   21 c -  16 "Dead demon"			SARGN
+thing   22 c -  16 "Dead cacodemon"		HEADL
+thing   23 c -  16 "Dead lost soul"		SKULK
+
+thing 2035 d -  10 "Barrel"			BAR1
+thing 7011 d -  10 "Unstable barrel [EDGE]"	BEXP	# FIXME cut off
+thing   72 d -  16 "Commander Keen"		KEEN
+thing   48 d -  16 "Technical column"		ELEC
+thing   30 d -  16 "Tall green pillar"		COL1
+thing   32 d -  16 "Tall red pillar"		COL3
+thing   31 d -  16 "Short green pillar"		COL2
+thing   33 d -  16 "Short red pillar"		COL4
+thing   36 d -  16 "Pillar w/heart"		COL5
+thing   37 d -  16 "Red pillar w/skull"		COL6
+thing   41 d -  16 "Evil eye"			CEYE
+thing   42 g -  16 "Floating skulls"		FSKU
+thing   47 d -  16 "Brown stub"			SMIT
+thing 7010 d -  16 "Grey stub [EDGE]"		SMT2
+thing   54 d -  32 "Brown tree"			TRE2
+thing   43 d -  16 "Grey tree"			TRE1
+
+thing   10 g -  16 "Mushed player"		PLAYW
+thing   12 g -  16 "Mushed player 2"		PLAYW
+thing   24 g -  16 "Pool of blood"		POL5
+thing   79 g -  16 "Pool of blood 2"		POB1
+thing   80 g -  16 "Pool of blood 3"		POB2
+thing   81 g -  16 "Pool of brains"		BRS1
+thing   27 g -  16 "Pole with skull"		POL4
+thing   28 g -  16 "Skewer with heads"		POL2
+thing   29 g -  16 "Pile of skulls"		POL3
+thing   25 g -  16 "Impaled body"		POL1
+thing   26 g -  16 "Impaled twitching"		POL6
+thing   49 g -  16 "Swaying body O"		GOR1
+thing   63 g -  16 "Swaying body"		GOR1
+thing   50 g -  16 "Hanging arms out O"		GOR2
+thing   59 g -  16 "Hanging arms out"		GOR2
+thing   53 g -  16 "Hanging leg O"		GOR5
+thing   62 g -  16 "Hanging leg"		GOR5
+thing   51 g -  16 "Hanging one-legged O"	GOR3	# FIXME cut off
+thing   61 g -  16 "Hanging one-legged"		GOR3
+thing   52 g -  16 "Hanging torso O"		GOR4
+thing   60 g -  16 "Hanging torso"		GOR4
+thing   73 g -  16 "Hanging no guts"		HDB1
+thing   74 g -  16 "Hanging no brain"		HDB2
+thing   75 g -  16 "H. torso looking down"	HDB3
+thing   76 g -  16 "H. torso open skull"	HDB4
+thing   77 g -  16 "H. torso looking up"	HDB5
+thing   78 g -  16 "H. torso w/o brain"		HDB6
+
+thing 2014 h -  20 "Health bonus"		BON1
+thing 2011 h -  20 "Stimpack"			STIM
+thing 2012 h -  20 "Medikit"			MEDI
+thing 2013 h -  20 "Supercharge"		SOUL
+thing 2015 h -  20 "Armor bonus"		BON2
+thing 2018 h -  20 "Armor"			ARM1
+thing 2019 h -  20 "Megaarmor"			ARM2
+thing   83 h -  20 "Megasphere"			MEGA
+
+thing    5 k -  20 "Blue keycard"		BKEY
+thing    6 k -  20 "Yellow keycard"		YKEY
+thing   13 k -  20 "Red keycard"		RKEY
+thing   40 k -  20 "Blue skull key"		BSKU
+thing   39 k -  20 "Yellow skull key"		YSKU
+thing   38 k -  20 "Red skull key"		RSKU
+
+thing 2028 l -  16 "Lamp"			COLU
+thing   85 l -  16 "Tall mercury lamp"		TLMP
+thing   86 l -  16 "Short mercury lamp"		TLP2
+thing   34 l -  16 "Candle"			CAND
+thing   35 l -  16 "Candelabra"			CBRA
+thing   44 l -  16 "Tall blue torch"		TBLU
+thing   45 l -  16 "Tall green torch"		TGRN
+thing   46 l -  16 "Tall red torch"		TRED
+thing   55 l -  16 "Short blue torch"		SMBT
+thing   56 l -  16 "Short green torch"		SMGT
+thing   57 l -  16 "Short red torch"		SMRT
+thing   70 l -  16 "Burning barrel"		FCAN
+
+thing 3004 m -  20 "Trooper"			POSS
+thing    9 m -  20 "Sergeant"			SPOS
+thing 3001 m -  20 "Imp"			TROO
+thing 3002 m -  30 "Demon"			SARG
+thing 3003 m -  24 "Baron of hell"		BOSS
+thing   58 m s  30 "Spectre"			SARG
+thing 3006 m -  16 "Lost soul"			SKUL
+thing 3005 m -  31 "Cacodemon"			HEAD
+thing    7 m - 128 "Spider mastermind"		SPID
+thing   16 m -  40 "Cyberdemon"			CYBR
+thing   84 m -  20 "Wolfenstein SS"		SSWV
+thing   65 m -  20 "Heavy weapon dude"		CPOS
+thing   69 m -  24 "Hell knight"		BOS2
+thing   68 m -  64 "Arachnotron"		BSPI
+thing 7102 m -  64 "Arachnotron mkII [EDGE]"	BSPIH
+thing   71 m -  31 "Pain elemental"		PAIN
+thing   66 m -  20 "Revenant"			SKEL
+thing 7100 m -  20 "Revenant mkII [EDGE]"	SKELJ
+thing   67 m -  48 "Mancubus"			FATT
+thing 7103 m -  48 "Mancubus mkII [EDGE]"	FATTH
+thing   64 m -  20 "Arch vile"			VILE
+thing   88 m -  16 "Boss brain"			BBRN
+thing   89 m -  16 "Boss shooter"		BOSFB
+thing   87 m -  16 "Spawn spot"			FIREF
+thing 7101 m -  64 "Imp spawner [EDGE]"		TFOGB
+
+thing    1 p -  16 "Player 1 start"		PLAY
+thing    2 p -  16 "Player 2 start"		PLAY
+thing    3 p -  16 "Player 3 start"		PLAY
+thing    4 p -  16 "Player 4 start"		PLAY
+thing  888 p -  12 "Dog [MBF]"
+thing   11 p -  16 "Deathmatch start"		PLAYF1
+thing   14 p -  16 "Teleport exit"		TFOG
+
+thing 2005 w -  20 "Chainsaw"			CSAW
+thing 2001 w -  20 "Shotgun"			SHOT
+thing   82 w -  20 "Super shotgun"		SGN2
+thing 2002 w -  20 "Chaingun"			MGUN
+thing 2003 w -  20 "Rocket launcher"		LAUN
+thing 2004 w -  20 "Plasma gun"			PLAS
+thing 2006 w -  20 "BFG9000"			BFUG
+
+thing 5001 s -  20 "Point pusher [Boom]"
+thing 5002 s -  20 "Point puller [Boom]"
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ygd/doompr.ygd	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,354 @@
+# Yadex game definition file version 4
+#
+#	doompr.ygd
+#	Yadex Game Definitions for Doom press release pre-beta
+#	(ftp://ftp.cdrom.com/pub/idgames/historic/doomprbt.zip)
+#	See doc/ygd.html for the specs.
+#	AYM 1999-07-09
+#
+
+# FIXME	probably needs work, especially in
+# the things definitions dept.
+
+level_format    doom
+level_name      e1m1
+picture_format  pr
+sky_flat        f_sky1
+texture_format  normal
+texture_lumps   normal
+
+#
+#	Definition of linedef type groups
+#	Format is : ldtgroup <ldtgroup> <description>
+#
+
+ldtgroup d "Door"
+ldtgroup r "Door (red key)"
+ldtgroup y "Door (yellow key)"
+ldtgroup b "Door (blue key)"
+ldtgroup D "Door (turbo)"
+ldtgroup l "Lift"
+ldtgroup F "Floor (raise)"
+ldtgroup f "Floor (lower)"
+ldtgroup c "Ceiling"
+ldtgroup C "Crushing ceiling"
+ldtgroup t "Teleport"
+ldtgroup L "Light"
+ldtgroup e "End level"
+ldtgroup m "Moving floor"
+ldtgroup s "Raising stairs"
+ldtgroup x "Misc."
+
+#
+#	Definition of linedef types
+#	Format is : ldt <number> <ldtgroup> <shortdesc> <longdesc>
+#	<shortdesc> must not exceed 16 characters.
+#
+
+ldt   0 x "-- Normal"        "--  Normal"
+ldt   1 d "DR Open door"     "DR  Open  door"
+ldt   2 d "W1 Open door (O)" "W1  Open  door (stays open)"
+ldt   3 d "W1 Close door"    "W1  Close door"
+ldt   4 d "W1 Open door"     "W1  Open  door"
+ldt   5 F "W1 Floor up LIC"  "W1  Raise floor to LIC"
+ldt   6 C "W1 Crush FF"      "W1  Start fast crushing, fast hurt"
+ldt   7 s "S1 Raise stairs"  "S1  Raise stairs (several sectors 0/999)"
+ldt   8 s "W1 Raise stairs"  "W1  Raise stairs (several sectors 0/999)"
+ldt   9 x "S1 Donut"         "S1  Lower floor, raise Ne. floor (NXP) 'Donut'"
+ldt  10 l "W1 Lower lift"    "W1  Lower lift"
+ldt  11 e "S- End level"     "S-  End level, go to next level"
+ldt  12 L "W1 Light to HE"   "W1  Light level goes to HE"
+ldt  13 L "W1 Light to 255"  "W1  Light level goes to 255"
+ldt  14 F "S1& F. up 32 TX"  "S1& Raise floor by 32 (TX)"
+ldt  15 F "S1& F. up 24 TX"  "S1& Raise floor by 24 (TX)"
+ldt  16 d "W1 Close for 30s" "W1  Close door for 30 seconds"
+ldt  17 L "W1 Start blink"   "W1  Start blinking lights"
+ldt  18 F "S1 Floor up nhEF" "S1  Raise floor to nhEF"
+ldt  19 f "W1 Floor dn HEF"  "W1  Lower floor to HEF"
+ldt  20 F "S1& F up nhEF TX" "S1& Raise floor to nhEF (TX)"
+ldt  21 l "S1 Lower lift"    "S1  Lower lift"
+ldt  22 F "W1& F up nhEF TX" "W1& Raise floor to nhEF (TX)"
+ldt  23 f "S1 Floor dn LEF"  "S1  Lower floor to LEF"
+ldt  24 F "G1 Floor up LIC"  "G1  Raise floor to LIC"
+ldt  25 C "W1 Crush FS"      "W1  Start fast crushing, slow hurt"
+ldt  26 b "DR Open blue dr"  "DR  Open  door, blue key"
+ldt  27 y "DR Open yel dr"   "DR  Open  door, yellow key"
+ldt  28 r "DR Open red dr"   "DR  Open  door, red key"
+ldt  29 d "S1 Open door"     "S1  Open  door"
+ldt  30 F "W1 Floor up SLT"  "W1  Raise floor by ShortestLowerTexture"
+ldt  31 d "D1 Open door (O)" "D1  Open  door (stays open)"
+ldt  32 b "D1 Open blu (O)"  "D1  Open  door (stays open), blue key"
+ldt  33 r "D1 Open red (O)"  "D1  Open  door (stays open), red key"
+ldt  34 y "D1 Open yel (O)"  "D1  Open  door (stays open), yellow key"
+ldt  35 L "W1 Light to 35"   "W1  Light level goes to 35"
+ldt  36 f "W1 F. DN HEF+8"   "W1  Lower turbo floor to HEF + 8"
+ldt  37 f "W1 F. dn LEF NXP" "W1  Lower floor to LEF (NXP)"
+ldt  38 f "W1 Floor dn LEF"  "W1  Lower floor to LEF"
+ldt  39 t "W1 Teleport"      "W1  Teleport to another sector"
+ldt  40 c "W1 Ceil up HEC"   "W1  Raise ceiling to HEC"
+ldt  41 c "S1 Ceil dn floor" "S1  Lower ceiling to floor"
+ldt  42 d "SR Close door"    "SR  Close door"
+ldt  43 c "SR Ceil dn floor" "SR  Lower ceiling to floor"
+ldt  44 c "W1 Ceil dn flr+8" "W1  Lower ceiling to floor + 8"
+ldt  45 f "SR Floor dn HEF"  "SR  Lower floor to HEF"
+ldt  46 d "GR Open door (O)" "GR  Open  door (stays open)"
+ldt  47 F "G1 F. up nhEF TX" "G1  Raise floor to nhEF (TX)"
+ldt  48 x "-- Animated wall" "--  Animated wall (scrolls horizontally)"
+ldt  49 c "S1 Ceil dn flr+8" "S1  Lower ceiling to floor + 8"
+ldt  50 d "S1 Close door"    "S1  Close door"
+ldt  51 e "S- Secret level"  "S-  End level, go to secret level"
+ldt  52 e "W- End level"     "W-  End level, go to next level"
+ldt  53 m "W1 Start moving"  "W1  Start moving floor"
+ldt  54 m "W1 Stop moving f" "W1  Stop  moving floor"
+ldt  55 F "S1 F. up LIC-8"   "S1  Raise floor to LIC - 8, crush"
+ldt  56 F "W1& F. up LIC-8"  "W1& Raise floor to LIC - 8, crush"
+ldt  57 C "W1& Stop crush"   "W1& Stop  crushing"
+ldt  58 F "W1 Floor up 24"   "W1  Raise floor by 24"
+ldt  59 F "W1 F. up 24 TXP"  "W1  Raise floor by 24 (TXP)"
+ldt  60 f "SR Floor dn LEF"  "SR  Lower floor to LEF"
+ldt  61 d "SR Open door (O)" "SR  Open  door (stays open)"
+ldt  62 l "SR Lower lift"    "SR  Lower lift"
+ldt  63 d "SR Open door"     "SR  Open  door"
+ldt  64 F "SR Floor up LIC"  "SR  Raise floor to LIC"
+ldt  65 F "SR F. up LIC-8"   "SR  Raise floor to LIC - 8, crush"
+ldt  66 F "SR& F. up 24 TX"  "SR& Raise floor by 24 (TX)"
+ldt  67 F "SR& F. up 32 TX"  "SR& Raise floor by 32 (TX)"
+ldt  68 f "SR& F up nhEF TX" "SR& Raise floor to nhEF (TX)"
+ldt  69 F "SR F. up nhEF"    "SR  Raise floor to nhEF"
+ldt  70 f "SR F. DN HEF+8"   "SR  Lower turbo floor to HEF + 8"
+ldt  71 f "S1 F. DN HEF+8"   "S1  Lower turbo floor to HEF + 8"
+ldt  72 c "WR Ceil dn flr+8" "WR  Lower ceiling to floor + 8"
+ldt  73 C "WR& Crush SS"     "WR& Start slow crushing, slow hurt"
+ldt  74 C "WR& Stop crush"   "WR& Stop  crushing"
+ldt  75 d "WR Close door"    "WR  Close door"
+ldt  76 d "WR Close for 30s" "WR  Close door for 30 seconds"
+ldt  77 C "WR& Crush FF"     "WR& Start fast crushing, fast hurt"
+#ldt 78 x "-- Unimplemented" "--  Unimplemented"
+ldt  79 L "WR Light to 35"   "WR  Light level goes to 35"
+ldt  80 L "WR Light to HE"   "WR  Light level goes to HE"
+ldt  81 L "WR Light to 255"  "WR  Light level goes to 255"
+ldt  82 f "WR Floor dn LEF"  "WR  Lower floor to LEF"
+ldt  83 f "WR Floor dn HEF"  "WR  Lower floor to HEF"
+ldt  84 f "WR F. dn LEF NXP" "WR  Lower floor to LEF (NXP)"
+#ldt 85 x "-- Unimplemented" "--  Unimplemented"
+ldt  86 d "WR Open door (O)" "WR  Open  door (stays open)"
+ldt  87 m "WR& Start moving" "WR& Start moving floor"
+ldt  88 l "WR Lower lift"    "WR  Lower lift"
+ldt  89 m "WR& Stop moving"  "WR& Stop  moving floor"
+ldt  90 d "WR Open door"     "WR  Open  door"
+ldt  91 F "WR Floor up LIC"  "WR  Raise floor to LIC"
+ldt  92 F "WR Floor up 24"   "WR  Raise floor by 24"
+ldt  93 F "WR F. up 24 TXP"  "WR  Raise floor by 24 (TXP)"
+ldt  94 F "WR F. up LIC-8"   "WR  Raise floor to LIC - 8, crush"
+ldt  95 F "WR F. up nhEF TX" "WR  Raise floor to nhEF (TX)"
+ldt  96 F "WR Floor up SLT"  "WR  Raise floor by ShortestLowerTexture"
+ldt  97 t "WR Teleport"      "WR  Teleport to another sector"
+ldt  98 f "WR F. DN HEF+8"   "WR  Lower turbo floor to HEF + 8"
+ldt  99 b "SR OPEN blu door" "SR  Open  turbo door, blue key [v1.6]"
+ldt 100 s "W1 RaiseStairs16" "W1  Raise stairs (step=16), crush [v1.6]"
+ldt 101 F "S1 Floor up LIC"  "S1  Raise floor to LIC"
+ldt 102 f "S1 Floor dn HEF"  "S1  Lower floor to HEF"
+ldt 103 d "S1 Open door (O)" "S1  Open  door (stays open)"
+ldt 104 L "W1 Light to LE"   "W1  Light level goes to LE"
+ldt 105 D "WR OPEN door"     "WR  Open  turbo door [v1.6]"
+ldt 106 D "WR OPEN door (O)" "WR  Open  turbo door (stays open) [v1.6]"
+ldt 107 D "WR CLOSE door"    "WR  Close turbo door [v1.6]"
+ldt 108 D "W1 OPEN door"     "W1  Open  turbo door [v1.6]"
+ldt 109 D "W1 OPEN door (O)" "W1  Open  turbo door (stays open) [v1.6]"
+ldt 110 D "W1 CLOSE door"    "W1  Close turbo door [v1.6]"
+ldt 111 D "S1 OPEN door"     "S1  Open  turbo door [v1.6]"
+ldt 112 D "S1 OPEN door (O)" "S1  Open  turbo door (stays open) [v1.6]"
+ldt 113 D "S1 CLOSE door"    "S1  Close turbo door [v1.6]"
+ldt 114 D "SR OPEN door"     "SR  Open  turbo door [v1.6]"
+ldt 115 D "SR OPEN door (O)" "SR  Open  turbo door (stays open) [v1.6]"
+ldt 116 D "SR CLOSE door"    "SR  Close turbo door [v1.6]"
+ldt 117 D "DR OPEN door"     "DR  Open  turbo door [v1.6]"
+ldt 118 D "D1 OPEN door (O)" "D1  Open  turbo door (stays open) [v1.6]"
+ldt 119 F "W1 Floor up nhEF" "W1  Raise floor to nhEF [v1.6]"
+ldt 120 l "WR LOWER lift"    "WR  Lower turbo lift [v1.6]"
+ldt 121 l "W1 LOWER lift"    "W1  Lower turbo lift [v1.6]"
+ldt 122 l "S1 LOWER lift"    "S1  Lower turbo lift [v1.6]"
+ldt 123 l "SR LOWER lift"    "SR  Lower turbo lift [v1.6]"
+ldt 124 e "W- Secret level"  "W-  End level, go to secret level [v1.6]"
+ldt 125 t "W1 Teleport mons" "W1  Teleport monsters only [v1.6]"
+ldt 126 t "WR Teleport mons" "WR  Teleport monsters only [v1.6]"
+ldt 127 s "S1 RaiseStairs16" "S1  Raise stairs (step=16), crush [v1.6]"
+ldt 128 F "WR Floor up nhEF" "WR  Raise floor to nhEF [v1.6]"
+ldt 129 F "WR Floor UP nhEF" "WR  Raise turbo floor to nhEF [v1.6]"
+ldt 130 F "W1 Floor UP nhEF" "W1  Raise turbo floor to nhEF [v1.6]"
+ldt 131 F "S1 Floor UP nhEF" "S1  Raise turbo floor to nhEF [v1.6]"
+ldt 132 F "SR Floor UP nhEF" "SR  Raise turbo floor to nhEF [v1.6]"
+ldt 133 b "S1 OPEN blu door" "S1  Open  turbo door, blue key [v1.6]"
+ldt 134 r "SR OPEN red door" "SR  Open  turbo door, red key [v1.6]"
+ldt 135 r "S1 OPEN red door" "S1  Open  turbo door, red key [v1.6]"
+ldt 136 y "SR OPEN yel door" "SR  Open  turbo door, yellow key [v1.6]"
+ldt 137 y "S1 OPEN yel door" "S1  Open  turbo door, yellow key [v1.6]"
+ldt 138 L "SR Light to 255"  "SR  Light level goes to 255 [v1.6]"
+ldt 139 L "SR Light to 0"    "SR  Light level goes to 0 [v1.6]"
+ldt 140 F "S1 Floor up 512"  "S1  Raise floor by 512, medium speed [v1.6]"
+ldt 141 C "W1& Crush SS sil" "W1& Start slow crushing, slow hurt, silent [v1.6]"
+ldt 271 x "-- Xfer sky"      "--  Xfer straight upper to sky tex. [MBF]"
+ldt 272 x "-- Xfer mir. sky" "--  Xfer mirrored upper to sky tex. [MBF]"
+
+#
+#	Definition of sector types
+#	Format is : st <number> <shortdesc> <longdesc>
+#	<shortdesc> must not exceed 14 characters.
+#
+
+st  0 "X Normal"       "X Normal"
+st  1 "  Blinks rand"  "  Light blinks randomly"
+st  2 "  Flashes 2 Hz" "  Light flashes 2 Hz"
+st  3 "  Flashes 1 Hz" "  Light flashes 1 Hz"
+st  4 "P -20% & 2Hz"   "P -10/20% health, flashes 2 Hz"
+st  5 "P -10% health"  "P -5/10% health"
+st  7 "P -5% health"   "P -2/5% health"
+st  8 "  Oscillates"   "  Light oscillates"
+st  9 "P Secret"       "P Secret"
+st 10 "  Closes 30 s"  "  30 s after level start, ceiling closes like a door"
+st 11 "P -20% & end"   "P -10/20% health and end level when health <= 10%"
+st 12 "  Flash1Hz syn" "  Light flashes 1 Hz, synchronized"
+st 13 "  Flash2Hz syn" "  Light flashes 2 Hz, synchronized"
+st 14 "  Opens 300 s"  "  300 s after level start, ceiling opens like a door"
+st 16 "P -20% health"  "P -10/20% health"
+st 17 "  Flicker rand" "  Light flickers on and off randomly [v1.6]"
+
+#
+#	Definition of thing groups
+#	Format is : thinggroup <thinggroup> <colour> <description>
+#
+
+thinggroup p rgb:4/f/4 "Player"
+thinggroup m rgb:f/0/0 "Monster"
+thinggroup w rgb:f/a/0 "Weapon"
+thinggroup a rgb:8/5/0 "Ammunition"
+thinggroup h rgb:2/8/0 "Health & armour"
+thinggroup b rgb:2/8/0 "Misc. bonus"
+thinggroup k rgb:f/0/f "Key"
+thinggroup d rgb:6/6/c "Misc. decoration"
+thinggroup l rgb:6/6/c "Light source"
+thinggroup g rgb:6/6/c "Gory decoration"
+thinggroup c rgb:6/6/c "Corpse"
+thinggroup s rgb:0/b/d "Special"
+
+#
+#	Definition of things
+#	Format is :
+#	thing <number> <thinggroup> <flags> <radius> <desc> [<sprite>]
+#	<desc> must not exceed 19 characters.
+#
+
+thing 2007 a -  20 "Clip"			CLIP
+thing 2048 a -  20 "Box of bullets"		AMMO
+thing 2008 a -  20 "4 shotgun shells"		SHEL
+thing 2049 a -  20 "Box shotgun shells"		SBOX
+thing 2010 a -  20 "Rocket"			ROCK
+thing 2046 a -  20 "Box of rockets"		BROK
+thing 2047 a -  20 "Energy cell"		CELL
+thing   17 a -  20 "Energy cell pack"		CELP
+thing    8 a -  20 "Backpack full ammo"		BPAK
+
+thing 2025 b -  20 "Rad. shielding suit"	SUIT
+thing 2026 b -  20 "Computer area map"		PMAP
+thing 2024 b -  20 "Partial invis."		PINS
+thing 2023 b -  20 "Berserk"			PSTR
+thing 2022 b -  20 "Invulnerability"		PINV
+thing 2045 b -  20 "Light amp. visor"		PVIS
+thing 2016 b -  16 "Evil sceptre [PR]"		BON3
+thing 2017 b -  16 "Unholy bible [PR]"		BON4
+
+thing   15 c -  16 "Dead player (green)"	PLAYN
+thing   18 c -  20 "Dead trooper"		POSSL
+thing   19 c -  20 "Dead sergeant"		SPOSL
+thing   20 c -  20 "Dead imp"			TROOM
+thing   21 c -  16 "Dead demon"			SARGN
+thing   22 c -  16 "Dead cacodemon"		HEADL
+thing   23 c -  16 "Dead lost soul"		SKULK
+
+thing 2035 d -  10 "Barrel"			BAR1
+thing   48 d -  16 "Technical column"		ELEC
+thing   30 d -  16 "Tall green pillar"		COL1
+thing   32 d -  16 "Tall red pillar"		COL3
+thing   31 d -  16 "Short green pillar"		COL2
+thing   33 d -  16 "Short red pillar"		COL4
+thing   36 d -  16 "Pillar w/heart"		COL5
+thing   37 d -  16 "Red pillar w/skull"		COL6
+thing   41 d -  16 "Evil eye"			CEYE
+thing   42 g -  16 "Floating skulls"		FSKU
+thing   43 d -  16 "Grey tree"			TRE1
+thing   47 d -  16 "Brown stub"			SMIT
+thing   54 d -  32 "Tall brown tree"		TRE2
+
+thing   10 g -  16 "Mushed player"		PLAYW
+thing   12 g -  16 "Mushed player 2"		PLAYW
+thing   24 g -  16 "Pool of blood"		POL5
+thing   27 g -  16 "Pole with skull"		POL4
+thing   28 g -  16 "Skewer with heads"		POL2
+thing   29 g -  16 "Pile of skulls"		POL3
+thing   25 g -  16 "Impaled body"		POL1
+thing   26 g -  16 "Impaled twitching"		POL6
+thing   49 g -  16 "Swaying body O"		GOR1
+thing   63 g -  16 "Swaying body"		GOR1
+thing   50 g -  16 "Hanging arms out O"		GOR2
+thing   59 g -  16 "Hanging arms out"		GOR2
+thing   53 g -  16 "Hanging leg O"		GOR5
+thing   62 g -  16 "Hanging leg"		GOR5
+thing   51 g -  16 "Hanging one-legged O"	GOR3	# FIXME cut off
+thing   61 g -  16 "Hanging one-legged"		GOR3
+thing   52 g -  16 "Hanging torso O"		GOR4
+thing   60 g -  16 "Hanging torso"		GOR4
+
+thing 2014 h -  20 "Health bonus"		BON1
+thing 2011 h -  20 "Stimpack"			STIM
+thing 2012 h -  20 "Medikit"			MEDI
+thing 2013 h -  20 "Supercharge"		SOUL
+thing 2015 h -  20 "Armor bonus"		BON2
+thing 2018 h -  20 "Armor"			ARM1
+thing 2019 h -  20 "Megaarmor"			ARM2
+
+thing    5 k -  20 "Blue keycard"		BKEY
+thing    6 k -  20 "Yellow keycard"		YKEY
+thing   13 k -  20 "Red keycard"		RKEY
+thing   40 k -  20 "Blue skull key"		BSKU
+thing   39 k -  20 "Yellow skull key"		YSKU
+thing   38 k -  20 "Red skull key"		RSKU
+
+thing 2028 l -  16 "Lamp"			COLU
+thing   34 l -  16 "Candle"			CAND
+thing   35 l -  16 "Candelabra"			CBRA
+thing   44 l -  16 "Tall blue torch"		TBLU
+thing   45 l -  16 "Tall green torch"		TGRN
+thing   46 l -  16 "Tall red torch"		TRED
+thing   55 l -  16 "Short blue torch"		SMBT
+thing   56 l -  16 "Short green torch"		SMGT
+thing   57 l -  16 "Short red torch"		SMRT
+
+thing 3004 m -  20 "Trooper"			POSS
+thing    9 m -  20 "Sergeant"			SPOS
+thing 3001 m -  20 "Imp"			TROO
+thing 3002 m -  30 "Demon"			SARG
+thing 3003 m -  24 "Baron of hell"		BOSS
+thing   58 m s  30 "Spectre"			SARG
+thing 3006 m -  16 "Lost soul"			SKUL
+thing 3005 m -  31 "Cacodemon"			HEAD
+thing    7 m - 128 "Spider mastermind"		SPID
+thing   16 m -  40 "Cyberdemon"			CYBR
+
+thing    1 p -  16 "Player 1 start"		PLAY
+thing    2 p -  16 "Player 2 start"		PLAY
+thing    3 p -  16 "Player 3 start"		PLAY
+thing    4 p -  16 "Player 4 start"		PLAY
+thing  888 p -  12 "Dog [MBF]"
+thing   11 p -  16 "Deathmatch start"		PLAYE1
+thing   14 p -  16 "Teleport exit"		TFOG
+
+thing 2005 w -  20 "Chainsaw"			CSAW
+thing 2001 w -  20 "Shotgun"			SHOT
+thing 2002 w -  20 "Chaingun"			MGUN
+thing 2003 w -  20 "Rocket launcher"		LAUN
+thing 2004 w -  20 "Plasma gun"			PLAS
+thing 2006 w -  20 "BFG9000"			BFUG
+
+thing 5001 s -  20 "Point pusher [Boom]"
+thing 5002 s -  20 "Point puller [Boom]"
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ygd/heretic.ygd	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,341 @@
+# Yadex game definition file version 4
+#
+#	heretic.ygd
+#	Yadex Game Definitions for Heretic
+#	See doc/ygd.html for the specs.
+#	AYM 1998-10-20
+#
+
+# With help from Barry Mead.
+
+level_format    doom
+level_name      e1m1
+picture_format  normal
+sky_flat        f_sky1
+texture_format  normal
+texture_lumps   normal
+
+#
+#	Definition of linedef type groups
+#	Format is : ldtgroup <ldtgroup> <description>
+#
+
+ldtgroup d "Door"
+ldtgroup y "Door (yellow key)"
+ldtgroup g "Door (green key)"
+ldtgroup b "Door (blue key)"
+ldtgroup l "Lift"
+ldtgroup F "Floor (raise)"
+ldtgroup f "Floor (lower)"
+ldtgroup c "Ceiling"
+ldtgroup C "Crushing ceiling"
+ldtgroup t "Teleport"
+ldtgroup L "Light"
+ldtgroup e "End level"
+ldtgroup m "Moving floor"
+ldtgroup s "Raising stairs"
+ldtgroup x "Misc."
+
+#
+#	Definition of linedef types
+#	Format is : ldt <number> <ldtgroup> <shortdesc> <longdesc>
+#	<shortdesc> must not exceed 16 characters.
+#
+
+ldt   0 x "-- Normal"        "--  Normal"
+ldt   1 d "DR Open door"     "DR  Open  door"
+ldt   2 d "W1 Open door (O)" "W1  Open  door (stays open)"
+ldt   3 d "W1 Close door"    "W1  Close door"
+ldt   4 d "W1 Open door"     "W1  Open  door"
+ldt   5 F "W1 Floor up LIC"  "W1  Raise floor to LIC"
+ldt   6 C "W1 Crush FF"      "W1  Start fast crushing, fast hurt"
+ldt   7 s "S1 Raise stairs"  "S1  Raise stairs (several sectors 0/999)"
+ldt   8 s "W1 Raise stairs"  "W1  Raise stairs (several sectors 0/999)"
+ldt   9 x "S1 Donut"         "S1  Lower floor, raise Ne. floor (NXP) 'Donut'"
+ldt  10 l "W1 Lower lift"    "W1  Lower lift"
+ldt  11 e "S- End level"     "S-  End level, go to next level"
+ldt  12 L "W1 Light to HE"   "W1  Light level goes to HE"
+ldt  13 L "W1 Light to 255"  "W1  Light level goes to 255"
+ldt  14 F "S1& F. up 32 TX"  "S1& Raise floor by 32 (TX)"
+ldt  15 F "S1& F. up 24 TX"  "S1& Raise floor by 24 (TX)"
+ldt  16 d "W1 Close for 30s" "W1  Close door for 30 seconds"
+ldt  17 L "W1 Start blink"   "W1  Start blinking lights"
+ldt  18 F "S1 Floor up nhEF" "S1  Raise floor to nhEF"
+ldt  19 f "W1 Floor dn HEF"  "W1  Lower floor to HEF"
+ldt  20 F "S1& F up nhEF TX" "S1& Raise floor to nhEF (TX)"
+ldt  21 l "S1 Lower lift"    "S1  Lower lift"
+ldt  22 F "W1& F up nhEF TX" "W1& Raise floor to nhEF (TX)"
+ldt  23 f "S1 Floor dn LEF"  "S1  Lower floor to LEF"
+ldt  24 F "G1 Floor up LIC"  "G1  Raise floor to LIC"
+ldt  25 C "W1 Crush FS"      "W1  Start fast crushing, slow hurt"
+ldt  26 b "DR Open blue dr"  "DR  Open  door, blue key"
+ldt  27 y "DR Open yel dr"   "DR  Open  door, yellow key"
+ldt  28 g "DR Open green dr" "DR  Open  door, green key"
+ldt  29 d "S1 Open door"     "S1  Open  door"
+ldt  30 F "W1 Floor up SLT"  "W1  Raise floor by ShortestLowerTexture"
+ldt  31 d "D1 Open door (O)" "D1  Open  door (stays open)"
+ldt  32 b "D1 Open blu (O)"  "D1  Open  door (stays open), blue key"
+ldt  33 g "D1 Open grn (O)"  "D1  Open  door (stays open), green key"
+ldt  34 y "D1 Open yel (O)"  "D1  Open  door (stays open), yellow key"
+ldt  35 L "W1 Light to 35"   "W1  Light level goes to 35"
+ldt  36 f "W1 F. DN HEF+8"   "W1  Lower turbo floor to HEF + 8"
+ldt  37 f "W1 F. dn LEF NXP" "W1  Lower floor to LEF (NXP)"
+ldt  38 f "W1 Floor dn LEF"  "W1  Lower floor to LEF"
+ldt  39 t "W1 Teleport"      "W1  Teleport to another sector"
+ldt  40 c "W1 CuHEC FdLEF"   "W1  Raise ceiling to HEC, lower floor to LEF"
+ldt  41 c "S1 Ceil dn floor" "S1  Lower ceiling to floor"
+ldt  42 d "SR Close door"    "SR  Close door"
+ldt  43 c "SR Ceil dn floor" "SR  Lower ceiling to floor"
+ldt  44 c "W1 C. dn f+8 cru" "W1  Lower ceiling to floor + 8"
+ldt  45 f "SR Floor dn HEF"  "SR  Lower floor to HEF"
+ldt  46 d "GR Open door (O)" "GR  Open  door (stays open)"
+ldt  47 F "G1 F. up nhEF TX" "G1  Raise floor to nhEF (TX)"
+ldt  48 x "-- Scroll left"   "--  Animated wall (scrolls left)"
+ldt  49 c "S1 C. dn f+8 cru" "S1  Lower ceiling to floor + 8"
+ldt  50 d "S1 Close door"    "S1  Close door"
+ldt  51 e "S- Secret level"  "S-  End level, go to secret level"
+ldt  52 e "W- End level"     "W-  End level, go to next level"
+ldt  53 m "W1 Start moving"  "W1  Start moving floor"
+ldt  54 m "W1 Stop moving f" "W1  Stop  moving floor"
+ldt  55 F "S1 F. up LIC-8"   "S1  Raise floor to LIC - 8, crush"
+ldt  56 F "W1& F. up LIC-8"  "W1& Raise floor to LIC - 8, crush"
+ldt  57 C "W1& Stop crush"   "W1& Stop  crushing"
+ldt  58 F "W1 Floor up 24"   "W1  Raise floor by 24"
+ldt  59 F "W1 F. up 24 TXP"  "W1  Raise floor by 24 (TXP)"
+ldt  60 f "SR Floor dn LEF"  "SR  Lower floor to LEF"
+ldt  61 d "SR Open door (O)" "SR  Open  door (stays open)"
+ldt  62 l "SR Lower lift"    "SR  Lower lift"
+ldt  63 d "SR Open door"     "SR  Open  door"
+ldt  64 F "SR Floor up LIC"  "SR  Raise floor to LIC"
+ldt  65 F "SR F. up LIC-8"   "SR  Raise floor to LIC - 8, crush"
+ldt  66 F "SR& F. up 24 TX"  "SR& Raise floor by 24 (TX)"
+ldt  67 F "SR& F. up 32 TX"  "SR& Raise floor by 32 (TX)"
+ldt  68 f "SR& F up nhEF TX" "SR& Raise floor to nhEF (TX)"
+ldt  69 F "SR F. up nhEF"    "SR  Raise floor to nhEF"
+ldt  70 f "SR F. DN HEF+8"   "SR  Lower turbo floor to HEF + 8"
+ldt  71 f "S1 F. DN HEF+8"   "S1  Lower turbo floor to HEF + 8"
+ldt  72 c "WR C. dn f+8 cru" "WR  Lower ceiling to floor + 8"
+ldt  73 C "WR& Crush SS"     "WR& Start slow crushing, slow hurt"
+ldt  74 C "WR& Stop crush"   "WR& Stop  crushing"
+ldt  75 d "WR Close door"    "WR  Close door"
+ldt  76 d "WR Close for 30s" "WR  Close door for 30 seconds"
+ldt  77 C "WR& Crush FF"     "WR& Start fast crushing, fast hurt"
+#ldt 78 x "-- Unimplemented" "--  Unimplemented"
+ldt  79 L "WR Light to 35"   "WR  Light level goes to 35"
+ldt  80 L "WR Light to HE"   "WR  Light level goes to HE"
+ldt  81 L "WR Light to 255"  "WR  Light level goes to 255"
+ldt  82 f "WR Floor dn LEF"  "WR  Lower floor to LEF"
+ldt  83 f "WR Floor dn HEF"  "WR  Lower floor to HEF"
+ldt  84 f "WR F. dn LEF NXP" "WR  Lower floor to LEF (NXP)"
+#ldt 85 x "-- Unimplemented" "--  Unimplemented"
+ldt  86 d "WR Open door (O)" "WR  Open  door (stays open)"
+ldt  87 m "WR& Start moving" "WR& Start moving floor"
+ldt  88 l "WR Lower lift"    "WR  Lower lift"
+ldt  89 m "WR& Stop moving"  "WR& Stop  moving floor"
+ldt  90 d "WR Open door"     "WR  Open  door"
+ldt  91 F "WR Floor up LIC"  "WR  Raise floor to LIC"
+ldt  92 F "WR Floor up 24"   "WR  Raise floor by 24"
+ldt  93 F "WR F. up 24 TXP"  "WR  Raise floor by 24 (TXP)"
+ldt  94 F "WR F. up LIC-8"   "WR  Raise floor to LIC - 8, crush"
+ldt  95 F "WR F. up nhEF TX" "WR  Raise floor to nhEF (TX)"
+ldt  96 F "WR Floor up SLT"  "WR  Raise floor by ShortestLowerTexture"
+ldt  97 t "WR Teleport"      "WR  Teleport to another sector"
+ldt  98 f "WR F. DN HEF+8"   "WR  Lower turbo floor to HEF + 8"
+ldt  99 x "-- Scroll right"  "--  Animated wall (scrolls right)"
+ldt 100 d "WR OPEN door"     "WR  Open  turbo door"
+ldt 101 F "S1 Floor up LIC"  "S1  Raise floor to LIC"
+ldt 102 f "S1 Floor dn HEF"  "S1  Lower floor to HEF"
+ldt 103 d "S1 Open door (O)" "S1  Open  door (stays open)"
+ldt 104 L "W1 Light to LE"   "W1  Light level goes to LE"
+ldt 105 e "W- Secret level"  "W-  End level, go to secret level"
+ldt 106 s "W1 Raise stairs"  "W1  Raise stairs, step 16"
+ldt 107 s "S1 Raise stairs"  "S1  Raise stairs, step 16"
+
+#
+#	Definition of sector types
+#	Format is : st <number> <shortdesc> <longdesc>
+#	<shortdesc> must not exceed 14 characters.
+#
+
+st  0 "X Normal"       "X Normal"
+st  1 "  Blinks rand"  "  Light blinks randomly"
+st  2 "  Flashes 2 Hz" "  Light flashes 2 Hz"
+st  3 "  Flashes 1 Hz" "  Light flashes 1 Hz"
+st  4 "P -10% flow E"  "P -5/10% health, floor scrolls eastward 28, flash 2 Hz"
+st  5 "P -10% health"  "P -5/10% health"
+st  6 "? Crush raise"  "? Ceiling crush and raise"
+st  7 "P -4% health"   "P -2/4% health"
+st  8 "  Oscillates"   "  Light oscillates"
+st  9 "P Secret"       "P Secret"
+st 10 "  Closes 30 s"  "  30 s after level start, ceiling closes like a door"
+st 12 "  Flash1Hz syn" "  Light flashes 1 Hz, synchronized"
+st 13 "  Flash2Hz syn" "  Light flashes 2 Hz, synchronized"
+st 14 "  Opens 300 s"  "  300 s after level start, ceiling opens like a door"
+st 15 "? Ice low fric" "? Ice low friction"
+st 16 "P -16% health"  "P -8/16% health"
+st 20 "? Flow E  5"    "? Floor scrolls eastward  5"
+st 21 "? Flow E 10"    "? Floor scrolls eastward 10"
+st 22 "? Flow E 25"    "? Floor scrolls eastward 25"
+st 23 "? Flow E 30"    "? Floor scrolls eastward 30"
+st 24 "? Flow E 35"    "? Floor scrolls eastward 35"
+st 25 "? Flow N  5"    "? Floor scrolls northward  5"
+st 26 "? Flow N 10"    "? Floor scrolls northward 10"
+st 27 "? Flow N 25"    "? Floor scrolls northward 25"
+st 28 "? Flow N 30"    "? Floor scrolls northward 30"
+st 29 "? Flow N 35"    "? Floor scrolls northward 35"
+st 30 "? Flow S  5"    "? Floor scrolls southward  5"
+st 31 "? Flow S 10"    "? Floor scrolls southward 10"
+st 32 "? Flow S 25"    "? Floor scrolls southward 25"
+st 33 "? Flow S 30"    "? Floor scrolls southward 30"
+st 34 "? Flow S 35"    "? Floor scrolls southward 35"
+st 35 "? Flow W  5"    "? Floor scrolls westward  5"
+st 36 "? Flow W 10"    "? Floor scrolls westward 10"
+st 37 "? Flow W 25"    "? Floor scrolls westward 25"
+st 38 "? Flow W 30"    "? Floor scrolls westward 30"
+st 39 "? Flow W 35"    "? Floor scrolls westward 35"
+st 40 "? Wind E slow"  "? Wind blows eastward slowly"
+st 41 "? Wind E mid"   "? Wind blows eastward"
+st 42 "? Wind E fast"  "? Wind blows eastward fast"
+st 43 "? Wind N slow"  "? Wind blows northward slowly" 
+st 44 "? Wind N mid"   "? Wind blows northward"
+st 45 "? Wind N fast"  "? Wind blows northward fast" 
+st 46 "? Wind S slow"  "? Wind blows southward slowly" 
+st 47 "? Wind S mid"   "? Wind blows southward"
+st 48 "? Wind S fast"  "? Wind blows southward fast" 
+st 49 "? Wind W slow"  "? Wind blows westward slowly" 
+st 50 "? Wind W mid"   "? Wind blows westward"
+st 51 "? Wind W fast"  "? Wind blows westward fast" 
+
+#
+#	Definition of thing groups
+#	Format is : thinggroup <thinggroup> <colour> <description>
+#
+
+thinggroup p rgb:4/f/4 "Player"
+thinggroup m rgb:f/0/0 "Monster"
+thinggroup w rgb:f/a/0 "Weapon"
+thinggroup a rgb:8/5/0 "Ammunition"
+thinggroup h rgb:2/8/0 "Health & armour"
+thinggroup b rgb:2/8/0 "Misc. bonus"
+thinggroup k rgb:f/0/f "Key"
+thinggroup d rgb:6/6/c "Misc. decoration"
+#thinggroup l rgb:6/6/c "Light source"
+#thinggroup g rgb:6/6/c "Gory decoration"
+#thinggroup c rgb:6/6/c "Corpse"
+thinggroup e rgb:0/b/d "Environment sound"
+thinggroup s rgb:0/b/d "Ambient sound"
+
+#
+#	Definition of things
+#	Format is :
+#	thing <number> <thinggroup> <flags> <radius> <desc> [<sprite>]
+#	<desc> must not exceed 19 characters.
+#
+
+thing    1 p -   16 "Player 1 start"		PLAY
+thing    2 p -   16 "Player 2 start"		PLAY
+thing    3 p -   16 "Player 3 start"		PLAY
+thing    4 p -   16 "Player 4 start"		PLAY
+thing   11 p -   16 "Deathmatch start"		PLAYF1
+thing   14 p -   20 "Teleport exit"		TELE
+
+thing   66 m -   16 "Gargoyle"			IMPX
+thing    5 m -   16 "Gargoyle leader"		IMPXD
+thing   68 m -   22 "Golem"			MUMM
+thing   69 m s   22 "Golem ghost"		MUMM
+thing   45 m -   22 "Golem leader"		MUMMY
+thing   46 m s   22 "Golem leader ghost"	MUMMY
+thing   64 m -   24 "Undead warrior"		KNIG
+thing   65 m s   24 "Undead warrior ghost"	KNIG
+thing   15 m -   16 "Disciple"			WZRD
+thing   70 m -   32 "Weredragon"		BEAS
+thing   90 m -   20 "Sabre claw"		CLNK
+thing    6 m -   40 "Ironlich"			HEAD
+thing    9 m -   28 "Maulotaur"			MNTR
+thing   92 m -   22 "Ophidian"			SNKE
+thing    7 m -   28 "D'Sparil"			SRCR
+thing   56 m -   17 "D'Sparil spot"		SOR2H
+
+thing 2005 w -   20 "Gauntlets"			WGNT
+thing 2001 w -   20 "Ethereal cross bow"	WBOW
+thing   53 w -   20 "Dragon claw"		WBLS
+thing 2004 w -   20 "Hellstaff"			WSKL
+thing 2003 w -   20 "Phoenix rod"		WPHX
+thing 2002 w -   20 "Mace"			WMCE
+
+thing   10 a -   20 "Wand crystal"		AMG1
+thing   12 a -   20 "Wand geode"		AMG2
+thing   18 a -   20 "Ethereal arrows"		AMC1
+thing   19 a -   20 "Ethereal quiver"		AMC2
+thing   54 a -   20 "Claw orb"			AMB1
+thing   55 a -   20 "Energy orb"		AMB2
+thing   20 a -   20 "Lesser runes"		AMS1
+thing   21 a -   20 "Greater runes"		AMS2
+thing   22 a -   20 "Flame orb"			AMP1
+thing   23 a -   20 "Inferno orb"		AMP2
+thing   13 a -   20 "Mace spheres"		AMM1
+thing   16 a -   20 "Pile of mace spheres"	AMM2
+
+thing   32 h -   20 "Mystic urn"		SPHL
+thing   81 h -   20 "Crystal vial"		PTN1
+thing   82 h -   20 "Quartz flask"		PTN2
+thing   85 h -   20 "Silver shield"		SHLD
+thing   31 h -   20 "Enchanted shield"		SHD2
+
+thing    8 b -   20 "Bag of holding"		BAGH
+thing   30 b -   20 "Morph ovum"		EGGC
+thing   34 b -   20 "Time bomb"			FBMB
+thing   83 b -   20 "Wings of wrath"		SOAR
+thing   75 b -   20 "Shadowsphere"		INVS
+thing   84 b -   20 "Ring of invuln."		INVU
+thing   35 b -   20 "Map scroll"		SPMP
+thing   36 b -   20 "Chaos device"		ATLP
+thing   86 b -   20 "Tome of power"		PWBK
+thing   33 b -   20 "Torch"			TRCH
+
+thing   73 k -   20 "Green key"			AKYY
+thing   79 k -   20 "Blue key	"		BKYY
+thing   80 k -   20 "Yellow key"		CKYY
+
+thing   44 d -   12 "Barrel"			BARL
+thing   47 d -   14 "Brown pillar"		BRPL
+thing   28 d -   20 "Chandelier"		CHDL
+thing   76 d -   16 "Fire brazier"		KFR1
+thing   51 d -    8 "Hanging corpse"		HCOR
+thing   94 d -   16 "Blue key statue"		KGZB
+thing   95 d -   16 "Green key statue"		KGZG
+thing   96 d -   16 "Yellow key statue"		KGZY
+thing   48 d -   20 "Moss 1"			MOS1
+thing   49 d -   20 "Moss 2"			MOS2
+thing   27 d -   12 "Serpent torch"		SRTC
+thing   26 d -   20 "Hanging skull 35"		SKH4
+thing   25 d -   20 "Hanging skull 45"		SKH3
+thing   24 d -   20 "Hanging skull 60"		SKH2
+thing   17 d -   20 "Hanging skull 70"		SKH1
+thing   29 d -   16 "Small pillar"		SMPL
+thing   50 d -   20 "Wall torch"		WTRH
+thing   74 d -   20 "Teleport glitter"		TGLTA
+thing   52 d -   20 "Exit glitter"		TGLTF
+thing   87 d -   12 "Volcano"			VLCO
+thing   37 d -    8 "Small stalagmite"		STGS
+thing   38 d -   12 "Large stalagmite"		STGL
+thing   39 d -    8 "Small stalactite"		STCS
+thing   40 d -   12 "Large stalactite"		STCL
+thing 2035 d -   16 "Pod"			PPOD
+thing   43 d -   20 "Pod generator"
+
+thing   41 e -   20 "Waterfall"
+thing   42 e -   20 "Wind"
+
+thing 1200 s -   16 "Scream"
+thing 1201 s -   16 "Squish"
+thing 1202 s -   16 "Water drip"
+thing 1203 s -   16 "Slow footsteps"
+thing 1204 s -   16 "Heart beat"
+thing 1205 s -   16 "Bells"
+thing 1206 s -   16 "Growl"
+thing 1207 s -   16 "Magic"
+thing 1208 s -   16 "Laughter"
+thing 1209 s -   16 "Fast footsteps"
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ygd/hexen.ygd	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,265 @@
+# Yadex game definition file version 4
+#
+#	hexen.ygd
+#	Yadex Game Definitions for Hexen
+#	See doc/ygd.html for the specs.
+#	AYM 1999-02-25
+#
+
+# FIXME lots of things are missing, some are even wrong.
+
+level_format    hexen
+level_name      map01
+picture_format  normal 
+sky_flat        f_sky
+texture_format  normal
+texture_lumps   normal
+
+#
+#	Definition of linedef type groups
+#	Format is : ldtgroup <ldtgroup> <description>
+#
+
+ldtgroup d "Door"
+ldtgroup l "Lift"
+ldtgroup e "Elevator"
+ldtgroup f "Floor"
+ldtgroup c "Ceiling"
+ldtgroup t "Teleport"
+ldtgroup L "Light"
+ldtgroup p "Polyobj"
+ldtgroup P "Pillar"
+ldtgroup q "Quake"
+ldtgroup t "Teleport"
+ldtgroup T "Things"
+ldtgroup s "Stairs"
+ldtgroup a "ACS"
+ldtgroup x "Misc."
+
+#
+#	Definition of linedef types
+#	Format is : ldt <number> <ldtgroup> <shortdesc> <longdesc>
+#	<shortdesc> must not exceed 16 characters.
+#
+
+ldt   0 x "-- Normal"        "--  Normal"
+ldt   1 p "?? Polyobj start" "??  Polyobj_StartLine"
+ldt   2 p "?? Rol polyobj"   "??  Polyobj_RotateLeft"
+ldt   3 p "?? Ror polyobj"   "??  Polyobj_RotateRight"
+ldt   4 p "?? Move poly"     "??  Polyobj_Move"
+ldt   5 p "?? Poly explicit" "??  Polyobj_ExplicitLine"
+ldt   6 p "?? Move8x poly"   "??  Polyobj_MoveTimes8"
+ldt   7 p "?? Polyobj swing" "??  Polyobj_DoorSwing"
+ldt   8 p "?? Polyobj slide" "??  Polyobj_DoorSlide"
+ldt  10 d "?? Close door"    "??  Door_Close"
+ldt  11 d "?? Open door"     "??  Door_Open"
+ldt  12 d "?? Raise door"    "??  Door_Raise"
+ldt  13 d "?? Raise locked"  "??  Door_LockedRaise"
+ldt  20 f "?? Lower floor"   "??  Floor_LowerByValue"
+ldt  21 f "?? Lower floor L" "??  Floor_LowerToLowest"
+ldt  22 f "?? Lower fl nl"   "??  Floor_LowerToNearest"
+ldt  23 f "?? Raise floor"   "??  Floor_RaiseByValue"
+ldt  24 f "?? Raise floor H" "??  Floor_RaiseToHighest"
+ldt  25 f "?? Raise fl nh"   "??  Floor_RaiseToNearest"
+ldt  26 s "?? Stairs down"   "??  Stairs_BuildDown"
+ldt  27 s "?? Stairs up"     "??  Stairs_BuildUp"
+ldt  28 f "?? Raise f crush" "??  Floor_RaiseAndCrush"
+ldt  29 P "?? Build pillar"  "??  Pillar_Build"
+ldt  30 P "?? Open pillar"   "??  Pillar_Open"
+ldt  31 s "?? Stairs dn syn" "??  Stairs_BuildDownSync"
+ldt  32 s "?? Stairs up syn" "??  Stairs_BuildUpSync"
+ldt  35 f "?? Raise8x floor" "??  Floor_RaiseByValueTimes8"
+ldt  36 f "?? Lower8x floor" "??  Floor_LowerByValueTimes8"
+ldt  40 c "?? Lower ceil va" "??  Ceiling_LowerByValue"
+ldt  41 c "?? Raise ceil va" "??  Ceiling_RaiseByValue"
+ldt  42 c "?? Ceil crush 1"  "??  Ceiling_CrushAndRaise"
+ldt  43 c "?? Ceil crush 2"  "??  Ceiling_LowerAndCrush"
+ldt  44 c "?? Stop ceilcrsh" "??  Ceiling_CrushStop"
+ldt  45 c "?? Ceil crush 3"  "??  Ceiling_CrushRaiseAndStay"
+ldt  46 f "?? Stop fl crush" "??  Floor_CrushStop"
+ldt  60 l "?? Raise plat"    "??  Plat_PerpetualRaise"
+ldt  61 l "?? Stop plat"     "??  Plat_Stop"
+ldt  62 l "?? Lower lift"    "??  Plat_DownWaitUpStay"
+ldt  63 l "?? Plat down"     "??  Plat_DownByValue"
+ldt  64 l "?? Raise lift"    "??  Plat_UpWaitDownStay"
+ldt  65 l "?? Plat up"       "??  Plat_UpByValue"
+ldt  66 f "?? Lower F insta" "??  Floor_LowerInstant"
+ldt  67 f "?? Raise F insta" "??  Floor_RaiseInstant"
+ldt  68 f "?? Move8x floor"  "??  Floor_MoveToValueTimes8"
+ldt  69 c "?? Move8x ceilng" "??  Ceiling_MoveToValueTimes8"
+ldt  70 t "?? Teleport"      "??  Teleport"
+ldt  71 t "?? Telept no fog" "??  Teleport_NoFog"
+ldt  72 T "?? Thrush thing"  "??  ThrustThing"
+ldt  73 T "?? Damage thing"  "??  DamageThing"
+ldt  74 x "?? Teleport map"  "??  Teleport_NewMap"
+ldt  75 x "?? Teleport end"  "??  Teleport_EndGame"
+ldt  80 a "?? Execute ACS"   "??  ACS_Execute"
+ldt  81 a "?? Suspend ACS"   "??  ACS_Suspend"
+ldt  82 a "?? Terminate ACS" "??  ACS_Terminate"
+ldt  83 a "?? Lock-exec ACS" "??  ACS_LockedExecute"
+ldt  90 p "?? Rol poly OR"   "??  Polyobj_OR_RotateLeft"
+ldt  91 p "?? Ror poly OR"   "??  Polyobj_OR_RotateRight"
+ldt  92 p "?? Move poly OR"  "??  Polyobj_OR_Move"
+ldt  93 p "?? Mov8x poly OR" "??  Polyobj_OR_MoveTimes8"
+ldt  94 P "?? Crush pillar"  "??  Pillar_BuildAndCrush"
+ldt  95 e "?? Lower fl+ceil" "??  FloorAndCeiling_LowerByValue"
+ldt  96 e "?? Raise fl+ceil" "??  FloorAndCeiling_RaiseByValue"
+ldt 100 x "?? Scroll left"   "??  Scroll_Texture_Left"
+ldt 101 x "?? Scroll right"  "??  Scroll_Texture_Right"
+ldt 102 x "?? Scroll up"     "??  Scroll_Texture_Up"
+ldt 103 x "?? Scroll down"   "??  Scroll_Texture_Down"
+ldt 110 L "?? Raise light"   "??  Light_RaiseByValue"
+ldt 111 L "?? Lower light"   "??  Light_LowerByValue"
+ldt 112 L "?? Set light"     "??  Light_ChangeToValue"
+ldt 113 L "?? Fade light"    "??  Light_Fade"
+ldt 114 L "?? Glow light"    "??  Light_Glow"
+ldt 115 L "?? Flicker light" "??  Light_Flicker"
+ldt 116 L "?? Strobe light"  "??  Light_Strobe"
+ldt 120 q "?? Radius quake"  "??  Radius_Quake"
+ldt 121 x "?? Set line id"   "??  Line_SetIdentification"
+ldt 129 x "?? Use pzzl item" "??  UsePuzzleItem"
+ldt 130 T "?? Activate thng" "??  Thing_Activate"
+ldt 131 T "?? Deact. thing"  "??  Thing_Deactivate"
+ldt 132 T "?? Remove thing"  "??  Thing_Remove"
+ldt 133 T "?? Destroy thing" "??  Thing_Destroy"
+ldt 134 T "?? Projectile th" "??  Thing_Projectile"
+ldt 135 T "?? Spawn thing"   "??  Thing_Spawn"
+ldt 136 T "?? Gravity thing" "??  Thing_ProjectileGravity"
+ldt 137 T "?? Spawn no fog"  "??  Thing_SpawnNoFog"
+ldt 138 q "?? Waggle floor"  "??  Floor_Waggle"
+ldt 140 x "?? Change sound"  "??  Sector_ChangeSound"
+
+#
+#	Definition of sector types
+#	Format is : st <number> <shortdesc> <longdesc>
+#	<shortdesc> must not exceed 14 characters.
+#
+
+st   0 "  Normal"       "Normal"
+st   1 "  Phased light" "light phased"           # FIXME
+st   2 "  Light start"  "lightsequencestart"     # FIXME
+st   3 "  Light specl1" "lightsequencespecial1"  # FIXME
+st   4 "  Light specl2" "lightsequencespecial2"  # FIXME
+st   9 "  Secret"       "Sector counts toward secret count"
+st  26 "  Stairs1"      "Stairs special 1"
+st  27 "  Stairs2"      "Stairs special 2"
+st  40 "  Wind east 1"  "Wind east force 1"
+st  41 "  Wind east 2"  "Wind east force 2"
+st  42 "  Wind east 3"  "Wind east force 3"
+st  43 "  Wind north 1" "Wind north force 1"
+st  44 "  Wind north 2" "Wind north force 2"
+st  45 "  Wind north 3" "Wind north force 3"
+st  46 "  Wind south 1" "Wind south force 1"
+st  47 "  Wind south 2" "Wind south force 2"
+st  48 "  Wind south 3" "Wind south force 3"
+st  49 "  Wind west 1"  "Wind west force 1"
+st  50 "  Wind west 2"  "Wind west force 2"
+st  51 "  Wind west 3"  "Wind west force 3"
+st 198 "  Lightning 64" "Indoor lightning, +64 units"
+st 199 "  Lightning 32" "Indoor lightning, +32 units"
+st 200 "  Sky2"         "Use MAPINFO sky2"
+st 201 "  Scroll N slo" "Scroll north slow"
+st 202 "  Scroll N med" "Scroll north medium"
+st 203 "  Scroll N fas" "Scroll north fast"
+st 204 "  Scroll E slo" "Scroll east slow"
+st 205 "  Scroll E med" "Scroll east medium"
+st 206 "  Scroll E fas" "Scroll east fast"
+st 207 "  Scroll S slo" "Scroll south slow"
+st 208 "  Scroll S med" "Scroll south medium"
+st 209 "  Scroll S fas" "Scroll south fast"
+st 210 "  Scroll W slo" "Scroll west slow"
+st 211 "  Scroll W med" "Scroll west medium"
+st 212 "  Scroll W fas" "Scroll west fast"
+st 213 "  Scroll NW S"  "Scroll northwest slow"
+st 214 "  Scroll NW M"  "Scroll northwest medium"
+st 215 "  Scroll NW F"  "Scroll northwest fast"
+st 216 "  Scroll NE S"  "Scroll northeast slow"
+st 217 "  Scroll NE M"  "Scroll northeast medium"
+st 218 "  Scroll NE F"  "Scroll northeast fast"
+st 219 "  Scroll SE S"  "Scroll southeast slow"
+st 220 "  Scroll SE M"  "Scroll southeast medium"
+st 221 "  Scroll SE F"  "Scroll southeast fast"
+st 222 "  Scroll SW S"  "Scroll southwest slow"
+st 223 "  Scroll SW M"  "Scroll southwest medium"
+st 224 "  Scroll SW F"  "Scroll southwest fast"
+
+#
+#	Definition of thing groups
+#	Format is : thinggroup <thinggroup> <colour> <description>
+#
+
+thinggroup p rgb:4/f/4 "Player"
+thinggroup m rgb:f/0/0 "Monster"
+thinggroup w rgb:f/a/0 "Weapon"
+thinggroup a rgb:8/5/0 "Ammunition"
+thinggroup h rgb:2/8/0 "Health & armour"
+thinggroup b rgb:2/8/0 "Misc. bonus"
+thinggroup k rgb:f/0/f "Key"
+thinggroup P rgb:6/6/c "Plants"
+thinggroup d rgb:6/6/c "Misc. decoration"
+thinggroup l rgb:6/6/c "Light source"
+#thinggroup g rgb:6/6/c "Gory decoration"
+#thinggroup c rgb:6/6/c "Corpse"
+thinggroup e rgb:0/b/d "Environment sound"
+thinggroup s rgb:0/b/d "Ambient sound"
+
+#
+#	Definition of things
+#	Format is :
+#	thing <number> <thinggroup> <flags> <radius> <desc> [<sprite>]
+#	<desc> must not exceed 19 characters.
+#
+
+thing     1 p -   16 "Player 1 start"		PLAY
+thing     2 p -   16 "Player 2 start"		PLAY
+thing     3 p -   16 "Player 3 start"		PLAY
+thing     4 p -   16 "Player 4 start"		PLAY
+thing    11 p -   16 "Deathmatch start"		PLAYF1
+thing    14 p -   16 "Teleport exit"		TELE
+
+thing    31 m -   32 "Demon"			DEMN
+thing   107 m -   20 "Centaur"			CENT
+thing   115 m -   20 "Centaur leader"		CENTF
+thing   120 m -   17 "Serpent leader"		SSPTK	# Not too sure...
+thing   121 m -   17 "Serpent"			SSDV	# Not too sure...
+thing  8020 m -   22 "Ice guy"			ICEY
+thing 10030 m -   25 "Ettin"			ETTN
+thing 10060 m -   20 "Fire demon"		FDMN
+
+thing    10 w -   17 "Serpent staff"		WCSS   # Cleric
+thing    53 w -   17 "Frost chards"		WMCS   # Mage
+thing  8010 w -   17 "Timon's axe"		WFAX   # Fighter
+
+thing   122 a -   17 "Blue manna"		MAN1
+thing   124 a -   17 "Green manna"		MAN2
+thing  8004 a -   17 "Combined manna"		MAN3
+
+thing    81 h -   17 "Crystal vial"		PTN1
+thing    82 h -   17 "Quartz flask"		PTN2
+thing  8000 h -   17 "Flechette"		PSBG
+thing  8007 h -   17 "Platinum helmet"		ARM3
+
+thing   314 k -   17 "Stone (?) key"		KEY7
+
+thing    26 P -   17 "Swamp tree tall"		TRE2
+thing    27 P -   17 "Swamp tree short"		TRE3
+thing    78 P -   17 "Tree leaning right"	TRE4
+thing    79 P -   17 "Tree leaning left"	TRE5
+thing    80 P -   17 "Gnarled tree right"	TRE6
+thing    87 P -   17 "Gnarled tree left"	TRE7
+thing  8062 P -   17 "Dead tree"		TRDT
+thing  8068 P -   17 "Conic tree"		XMAS
+
+thing    48 d -   17 "Stalactite+gmite"		SGMP
+thing    72 d -   17 "Statue"			STT2
+thing    74 d -   17 "Short statue"		STT4
+thing    77 d -   17 "Banner"			BNR1
+
+thing    54 l -   17 "Torch"			WLTR
+thing  8061 l -   17 "FIXME"			BRTR
+
+thing   314 e -   17 "Bogus sound"
+
+thing   314 s -   17 "Bogus sound"
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ygd/strife.ygd	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,418 @@
+# Yadex game definition file version 4
+#
+#	strife.ygd
+#	Yadex Game Definitions for Strife (version 1.1 and above)
+#	AYM 1999-02-27
+#	mattm 2000.05.05 05.29
+#
+
+# FIXME this file contains many inaccuracies and
+# errors ;
+# - most things types are missing
+# - most new (w.r.t. Doom) linedef types are
+#   missing.
+# - some redefined (w.r.t. Doom) linedef types
+#   still have the Doom definition.
+# - some sector types may be missing (or wrong).
+# Anyone who knows Strife want to fix it ?
+
+level_format    doom
+level_name      map01
+picture_format  normal
+sky_flat        f_sky001
+texture_format  strife11
+texture_lumps   normal
+
+#
+#	Definition of linedef type groups
+#	Format is : ldtgroup <ldtgroup> <description>
+#
+
+ldtgroup d "Door"
+ldtgroup r "Door (red key)"
+ldtgroup y "Door (yellow key)"
+ldtgroup b "Door (blue key)"
+ldtgroup D "Door (turbo)"
+ldtgroup a "Door (animated)"
+ldtgroup l "Lift"
+ldtgroup F "Floor (raise)"
+ldtgroup f "Floor (lower)"
+ldtgroup c "Ceiling"
+ldtgroup C "Crushing ceiling"
+ldtgroup t "Teleport"
+ldtgroup L "Light"
+ldtgroup e "End level"
+ldtgroup m "Moving floor"
+ldtgroup s "Raising stairs"
+#ldtgroup B "Force fields"
+ldtgroup x "Misc."
+
+#
+#	Definition of linedef types
+#	Format is : ldt <number> <ldtgroup> <shortdesc> <longdesc>
+#	<shortdesc> must not exceed 16 characters.
+#
+
+ldt   0 x "-- Normal"        "--  Normal"
+ldt   1 d "DR Open door"     "DR  Open  door"
+ldt   2 d "W1 Open door (O)" "W1  Open  door (stays open)"
+ldt   3 d "W1 Close door"    "W1  Close door"
+ldt   4 d "W1 Open door"     "W1  Open  door"
+ldt   5 F "W1 Floor up LIC"  "W1  Raise floor to LIC"
+ldt   6 C "W1 Crush FF"      "W1  Start fast crushing, fast hurt"
+ldt   7 s "S1 Raise stairs"  "S1  Raise stairs (several sectors 0/999)"
+ldt   8 s "W1 Raise stairs"  "W1  Raise stairs (several sectors 0/999)"
+ldt   9 x "S1 Donut"         "S1  Lower floor, raise Ne. floor (NXP) 'Donut'"
+ldt  10 l "W1 Lower lift"    "W1  Lower lift"
+ldt  11 e "S- End level"     "S-  End level, go to next level"
+ldt  12 L "W1 Light to HE"   "W1  Light level goes to HE"
+ldt  13 L "W1 Light to 255"  "W1  Light level goes to 255"
+ldt  14 F "S1& F. up 32 TX"  "S1& Raise floor by 32 (TX)"
+ldt  15 F "S1& F. up 24 TX"  "S1& Raise floor by 24 (TX)"
+ldt  16 d "W1 Close for 30s" "W1  Close door for 30 seconds"
+ldt  17 L "W1 Start blink"   "W1  Start blinking lights"
+ldt  18 F "S1 Floor up nhEF" "S1  Raise floor to nhEF"
+ldt  19 f "W1 Floor dn HEF"  "W1  Lower floor to HEF"
+ldt  20 F "S1& F up nhEF TX" "S1& Raise floor to nhEF (TX)"
+ldt  21 l "S1 Lower lift"    "S1  Lower lift"
+ldt  22 F "W1& F up nhEF TX" "W1& Raise floor to nhEF (TX)"
+ldt  23 f "S1 Floor dn LEF"  "S1  Lower floor to LEF"
+ldt  24 F "G1 Floor up LIC"  "G1  Raise floor to LIC"
+ldt  25 C "W1 Crush FS"      "W1  Start fast crushing, slow hurt"
+ldt  26 b "DR Open blue dr"  "DR  Open  door, blue key"
+ldt  27 y "DR Open yel dr"   "DR  Open  door, yellow key"
+ldt  28 r "DR Open red dr"   "DR  Open  door, red key"
+ldt  29 d "S1 Open door"     "S1  Open  door"
+ldt  30 F "W1 Floor up SLT"  "W1  Raise floor by ShortestLowerTexture"
+ldt  31 d "D1 Open door (O)" "D1  Open  door (stays open)"
+ldt  32 b "D1 Open blu (O)"  "D1  Open  door (stays open), blue key"
+ldt  33 r "D1 Open red (O)"  "D1  Open  door (stays open), red key"
+ldt  34 y "D1 Open yel (O)"  "D1  Open  door (stays open), yellow key"
+ldt  35 L "W1 Light to 35"   "W1  Light level goes to 35"
+ldt  36 f "W1 F. DN HEF+8"   "W1  Lower turbo floor to HEF + 8"
+ldt  37 f "W1 F. dn LEF NXP" "W1  Lower floor to LEF (NXP)"
+ldt  38 f "W1 Floor dn LEF"  "W1  Lower floor to LEF"
+ldt  39 t "W1 Teleport"      "W1  Teleport to another sector"
+ldt  40 c "W1 Ceil up HEC"   "W1  Raise ceiling to HEC"
+ldt  41 c "S1 Ceil dn floor" "S1  Lower ceiling to floor"
+ldt  42 d "SR Close door"    "SR  Close door"
+ldt  43 c "SR Ceil dn floor" "SR  Lower ceiling to floor"
+ldt  44 c "W1 Ceil dn flr+8" "W1  Lower ceiling to floor + 8"
+ldt  45 f "SR Floor dn HEF"  "SR  Lower floor to HEF"
+ldt  46 d "GR Open door (O)" "GR  Open  door (stays open)"
+ldt  47 F "G1 F. up nhEF TX" "G1  Raise floor to nhEF (TX)"
+ldt  48 x "-- Scroll left"   "--  Animated wall (scrolls leftward)"
+ldt  49 c "S1 Ceil dn flr+8" "S1  Lower ceiling to floor + 8"
+ldt  50 d "S1 Close door"    "S1  Close door"
+ldt  51 e "S- Secret level"  "S-  End level, go to secret level"
+ldt  52 e "W- End level"     "W-  End level, go to next level"
+ldt  53 m "W1 Start moving"  "W1  Start moving floor"
+ldt  54 m "W1 Stop moving f" "W1  Stop  moving floor"
+ldt  55 F "S1 F. up LIC-8"   "S1  Raise floor to LIC - 8, crush"
+ldt  56 F "W1& F. up LIC-8"  "W1& Raise floor to LIC - 8, crush"
+ldt  57 C "W1& Stop crush"   "W1& Stop  crushing"
+ldt  58 F "W1 Floor up 24"   "W1  Raise floor by 24"
+ldt  59 F "W1 F. up 24 TXP"  "W1  Raise floor by 24 (TXP)"
+ldt  60 f "SR Floor dn LEF"  "SR  Lower floor to LEF"
+ldt  61 d "SR Open door (O)" "SR  Open  door (stays open)"
+ldt  62 l "SR Lower lift"    "SR  Lower lift"
+ldt  63 d "SR Open door"     "SR  Open  door"
+ldt  64 F "SR Floor up LIC"  "SR  Raise floor to LIC"
+ldt  65 F "SR F. up LIC-8"   "SR  Raise floor to LIC - 8, crush"
+ldt  66 F "SR& F. up 24 TX"  "SR& Raise floor by 24 (TX)"
+ldt  67 F "SR& F. up 32 TX"  "SR& Raise floor by 32 (TX)"
+ldt  68 f "SR& F up nhEF TX" "SR& Raise floor to nhEF (TX)"
+ldt  69 F "SR F. up nhEF"    "SR  Raise floor to nhEF"
+ldt  70 f "SR F. DN HEF+8"   "SR  Lower turbo floor to HEF + 8"
+ldt  71 f "S1 F. DN HEF+8"   "S1  Lower turbo floor to HEF + 8"
+ldt  72 c "WR Ceil dn flr+8" "WR  Lower ceiling to floor + 8"
+ldt  73 C "WR& Crush SS"     "WR& Start slow crushing, slow hurt"
+ldt  74 C "WR& Stop crush"   "WR& Stop  crushing"
+ldt  75 d "WR Close door"    "WR  Close door"
+ldt  76 d "WR Close for 30s" "WR  Close door for 30 seconds"
+ldt  77 C "WR& Crush FF"     "WR& Start fast crushing, fast hurt"
+#ldt 78 x "-- Unimplemented" "--  Unimplemented"
+ldt  79 L "WR Light to 35"   "WR  Light level goes to 35"
+ldt  80 L "WR Light to HE"   "WR  Light level goes to HE"
+ldt  81 L "WR Light to 255"  "WR  Light level goes to 255"
+ldt  82 f "WR Floor dn LEF"  "WR  Lower floor to LEF"
+ldt  83 f "WR Floor dn HEF"  "WR  Lower floor to HEF"
+ldt  84 f "WR F. dn LEF NXP" "WR  Lower floor to LEF (NXP)"
+#ldt 85 x "-- Unimplemented" "--  Unimplemented"
+ldt  86 d "WR Open door (O)" "WR  Open  door (stays open)"
+ldt  87 m "WR& Start moving" "WR& Start moving floor"
+ldt  88 l "WR Lower lift"    "WR  Lower lift"
+ldt  89 m "WR& Stop moving"  "WR& Stop  moving floor"
+ldt  90 d "WR Open door"     "WR  Open  door"
+ldt  91 F "WR Floor up LIC"  "WR  Raise floor to LIC"
+ldt  92 F "WR Floor up 24"   "WR  Raise floor by 24"
+ldt  93 F "WR F. up 24 TXP"  "WR  Raise floor by 24 (TXP)"
+ldt  94 F "WR F. up LIC-8"   "WR  Raise floor to LIC - 8, crush"
+ldt  95 F "WR F. up nhEF TX" "WR  Raise floor to nhEF (TX)"
+ldt  96 F "WR Floor up SLT"  "WR  Raise floor by ShortestLowerTexture"
+ldt  97 t "WR Teleport"      "WR  Teleport to another sector"
+ldt  98 f "WR F. DN HEF+8"   "WR  Lower turbo floor to HEF + 8"
+ldt  99 b "SR OPEN blu door" "SR  Open  turbo door, blue key [v1.6]"
+ldt 100 s "W1 RaiseStairs16" "W1  Raise stairs (step=16), crush [v1.6]"
+ldt 101 F "S1 Floor up LIC"  "S1  Raise floor to LIC"
+ldt 102 f "S1 Floor dn HEF"  "S1  Lower floor to HEF"
+ldt 103 d "S1 Open door (O)" "S1  Open  door (stays open)"
+ldt 104 L "W1 Light to LE"   "W1  Light level goes to LE"
+ldt 105 D "WR OPEN door"     "WR  Open  turbo door [v1.6]"
+ldt 106 D "WR OPEN door (O)" "WR  Open  turbo door (stays open) [v1.6]"
+ldt 107 D "WR CLOSE door"    "WR  Close turbo door [v1.6]"
+ldt 108 D "W1 OPEN door"     "W1  Open  turbo door [v1.6]"
+ldt 109 D "W1 OPEN door (O)" "W1  Open  turbo door (stays open) [v1.6]"
+ldt 110 D "W1 CLOSE door"    "W1  Close turbo door [v1.6]"
+ldt 111 D "S1 OPEN door"     "S1  Open  turbo door [v1.6]"
+ldt 112 D "S1 OPEN door (O)" "S1  Open  turbo door (stays open) [v1.6]"
+ldt 113 D "S1 CLOSE door"    "S1  Close turbo door [v1.6]"
+ldt 114 D "SR OPEN door"     "SR  Open  turbo door [v1.6]"
+ldt 115 D "SR OPEN door (O)" "SR  Open  turbo door (stays open) [v1.6]"
+ldt 116 D "SR CLOSE door"    "SR  Close turbo door [v1.6]"
+ldt 117 D "DR OPEN door"     "DR  Open  turbo door [v1.6]"
+ldt 118 D "D1 OPEN door (O)" "D1  Open  turbo door (stays open) [v1.6]"
+ldt 119 F "W1 Floor up nhEF" "W1  Raise floor to nhEF [v1.6]"
+ldt 120 l "WR LOWER lift"    "WR  Lower turbo lift [v1.6]"
+ldt 121 l "W1 LOWER lift"    "W1  Lower turbo lift [v1.6]"
+ldt 122 l "S1 LOWER lift"    "S1  Lower turbo lift [v1.6]"
+ldt 123 l "SR LOWER lift"    "SR  Lower turbo lift [v1.6]"
+ldt 124 e "W- Secret level"  "W-  End level, go to secret level [v1.6]"
+ldt 125 t "W1 Teleport mons" "W1  Teleport monsters only [v1.6]"
+ldt 126 t "WR Teleport mons" "WR  Teleport monsters only [v1.6]"
+ldt 127 s "S1 RaiseStairs16" "S1  Raise stairs (step=16), crush [v1.6]"
+ldt 128 F "WR Floor up nhEF" "WR  Raise floor to nhEF [v1.6]"
+ldt 129 F "WR Floor UP nhEF" "WR  Raise turbo floor to nhEF [v1.6]"
+ldt 130 F "W1 Floor UP nhEF" "W1  Raise turbo floor to nhEF [v1.6]"
+ldt 131 F "S1 Floor UP nhEF" "S1  Raise turbo floor to nhEF [v1.6]"
+ldt 132 F "SR Floor UP nhEF" "SR  Raise turbo floor to nhEF [v1.6]"
+ldt 133 b "S1 OPEN blu door" "S1  Open  turbo door, blue key [v1.6]"
+ldt 134 r "SR OPEN red door" "SR  Open  turbo door, red key [v1.6]"
+ldt 135 r "S1 OPEN red door" "S1  Open  turbo door, red key [v1.6]"
+ldt 136 y "SR OPEN yel door" "SR  Open  turbo door, yellow key [v1.6]"
+ldt 137 y "S1 OPEN yel door" "S1  Open  turbo door, yellow key [v1.6]"
+ldt 138 L "SR Light to 255"  "SR  Light level goes to 255 [v1.6]"
+ldt 139 L "SR Light to 0"    "SR  Light level goes to 0 [v1.6]"
+ldt 140 F "S1 Floor up 512"  "S1  Raise floor by 512, medium speed [v1.6]"
+ldt 141 C "W1& Crush SS sil" "W1& Start slow crushing, slow hurt, silent [v1.6]"
+ldt 143 x "-- Scroll down"   "--  Animated wall (scrolls downward)"
+ldt 144 a "XR Open animated" "XR  Open animated door"
+ldt 147 x "S1 Deac. FField"  "S1  Deactivate force field"
+ldt 148 x "-- Force Field"   "--  Force field, attempting to 'use' hurts"
+ldt 150 x "WR Sound alarms"  "WR  Sound alarms; alert Acolytes, Templars, etc"
+ldt 155 l "SR Raise lift"    "SR  Raise lift"
+ldt 165 x "-- Doesn't work"  "--  Print 'That doesn't seem to work' message"
+ldt 182 x "G1 Smashable"     "--  Smashable"
+ldt 185 t "W? STport ?"      "W?  Silent teleport <?>"
+ldt 195 t "W? STport, Aco."  "W?  Silent teleport <?>, become dummy Acolyte"
+ldt 205 x "SR 'Reg. only'"   "SR  Print 'registered version only' message"
+
+#
+#	Definition of sector types
+#	Format is : st <number> <shortdesc> <longdesc>
+#	<shortdesc> must not exceed 14 characters.
+#
+
+st  0 "X Normal"       "X Normal"
+st  1 "  Blinks rand"  "  Light blinks randomly"
+st  2 "  Flashes 2 Hz" "  Light flashes 2 Hz"
+st  3 "  Flashes 1 Hz" "  Light flashes 1 Hz"
+st  4 "P -20% & 2Hz"   "P -10/20% health, flashes 2 Hz"
+st  5 "P -10% health"  "P -5/10% health"
+st  7 "P -5% health"   "P -2/5% health"
+st  8 "  Oscillates"   "  Light oscillates"
+st  9 "P Secret"       "P Secret"
+st 10 "  Closes 30 s"  "  30 s after level start, ceiling closes like a door"
+st 11 "P -20% & end"   "P -10/20% health and end level when health <= 10%"
+st 12 "  Flash1Hz syn" "  Light flashes 1 Hz, synchronized"
+st 13 "  Flash2Hz syn" "  Light flashes 2 Hz, synchronized"
+st 14 "  Opens 300 s"  "  300 s after level start, ceiling opens like a door"
+st 15 "  Instant kill" "  Things standing on the sector are killed instantly"
+st 16 "P -20% health"  "P -10/20% health"
+st 17 "  Flicker rand" "  Light flickers on and off randomly [v1.6]"
+st 18 "  Push objects" "  Push objects (speed and angle depend on tag)"
+
+#
+#	Definition of thing groups
+#	Format is : thinggroup <thinggroup> <colour> <description>
+#
+
+thinggroup p rgb:0/f/0 "Player"
+thinggroup f rgb:0/b/0 "Friend"
+thinggroup e rgb:f/0/0 "Enemy"
+#thinggroup E rgb:f/8/8 "Enemy w/key"
+thinggroup n rgb:d/d/0 "Other character"
+thinggroup h rgb:2/8/0 "Health & armour"
+thinggroup w rgb:f/a/0 "Weapon"
+thinggroup a rgb:8/5/0 "Ammunition"
+thinggroup b rgb:2/8/0 "Misc. bonus"
+thinggroup k rgb:f/0/f "Key/trinket"
+thinggroup t rgb:0/a/0 "Cross-map teleport"
+#thinggroup s rgb:0/b/d "Special"
+thinggroup d rgb:6/6/c "Decoration"
+thinggroup l rgb:6/6/c "Lighting"
+thinggroup c rgb:6/6/c "Corpse"
+
+#
+#	Definition of things
+#	Format is : thing <number> <thinggroup> <flags> <radius> <description>
+#	<description> must not exceed 19 characters  --mattm
+#
+
+thing   22 d -   10 "Crusader wreck"		ROB2P
+thing   24 d -   10 "Siren"			KLAX
+thing   33 d -   16 "Dead tree"			TRE1
+thing   44 d -   16 "Statue"			STAT
+thing   46 d -   17 "Lantern"			LANT
+thing   48 d -   16 "Electrical column"		MONI
+thing   50 d -   17 "Torch on a stand"		LOGS
+thing   51 d -   16 "Palm tree"			TREEA
+thing   60 d -   10 "Small shrub"		BUSH
+thing   62 d -   10 "Shrub"			SHRB
+thing   82 d -   10 "Wood barrel"		BARW
+thing   94 d -   10 "Barrel"			BART
+thing  112 d -   10 "Fountain"			WTFT
+thing  165 d -   10 "Mug"			MUGG
+thing  194 d -   20 "Anvil"			ANVL
+thing  202 d -   16 "Tree"			TREEB
+thing  215 d -   16 "Wood in water"		LOGG
+#thing widths below are guesses  --mattm
+# Mine are even worse: they're just random. --AYM
+thing   23 d -   32 "Teleporter marker"		TELP
+thing   70 d -   16 "Flaming barrel?"		BARL
+thing  103 d -    4 "Dripping water pt 1?"	DRIPC
+thing   53 d -    4 "Dripping water pt 2?"	DRIPC
+thing  204 d -   16 "Holographic monk"		NEAL
+thing  208 d -   16 "Gun range target"		HOGN
+thing   85 d -   12 "Rat"			RATTB2B8
+thing  189 d -   16 "Three-Legged stool"	STOL
+thing  117 d -   16 "Medical device"		CRAB
+
+thing 2011 h -   20 "Med patch"			STMP
+thing 2012 h -   20 "Medical kit"		MDKT
+thing 2018 h -   17 "Leather armor"		ARM2
+thing 2019 h -   17 "Metal armor"		ARM1
+thing 2024 h -   20 "Shadow armor"		SHD1
+
+thing   34 l -   16 "Candle"			CNDL
+thing   95 l -    8 "Grey FT lamp"		LITS
+thing  107 l -    8 "Wall torch"		TRCH
+#thing widths below are guesses  --mattm
+thing  225 l -   16 "Alien lamp"		SPDL
+thing  106 l -   16 "Brazier"			BRAZ
+thing  105 l -   16 "Bowl with fire"		BOWL
+
+thing   58 e -   20 "Beige Acolyte"		AGRD
+thing  147 e -   20 "Green Acolyte"		AGRD
+thing  148 e -   20 "Acolyte (red ?)"		AGRD
+thing 3002 e -   20 "Beige Acolyte"		AGRD
+thing  143 e -   20 "Brown Acolyte"		AGRD
+#thing widths below are guesses  --mattm
+thing  146 e -   20 "Aggressive Acolyte"	AGRDF8
+thing  142 e -   20 "Acolyte w/key"		AGRD
+thing  186 e -   16 "Stalker"			SPIDJ #1st rightsideup --mattm
+thing 3006 e -   20 "Sentinel"			SEWRC1
+thing 3003 e -   20 "Templar"			PGRD
+thing 3001 e -   20 "Reaver"			ROB1
+thing 3005 e -   24 "Crusader"			ROB2
+thing   16 e -   32 "Inquisitor"		ROB3
+thing   71 e -   20 "Programmer?"		PRGRH0
+thing  187 e -   20 "Bishop?"			MLDR
+thing   76 e -   20 "Oracle's specter"		ALN1
+thing   12 e -   20 "Loremaster"		PRST
+thing   26 e -   20 "Entity nest? (pod?)"	NEST
+thing  198 e -   20 "Entity pod? (nest?)"	PODD
+thing   27 e -   17 "Turret"			TURT
+
+thing   72 n -   16 "Bar keeper"		MRBD # Brownish, sandy brown
+thing   73 n -   16 "Armourer"			MRBD # Nat, nat
+thing  116 n -   16 "Bowyer/Feris"		MRBD # Green, black
+thing   65 n -   20 "Harris"			PEAS # Red
+thing  130 n -   20 "Peasant (beige)"		PEAS # Default (beige)
+thing  132 n -   20 "Harris"			PEAS # Red
+thing  137 n -   20 "Peasant (brown)"		PEAS # Brown
+thing  169 n -   20 "Spawned peasant"		PEAS # Red
+thing  170 n -   20 "Peasant spawner"		PEAS # Red
+thing  173 n -   20 "Peasant (green)"		PEAS # Green
+thing  181 n -   20 "Governor Mourel"		PEAS # Cyan
+thing 3004 n -   20 "Peasant (beige)"		PEAS # Default (beige)
+thing  172 n -   20 "Richter"			PEAS # Dark green
+#Thing widths below are guesses  --mattm
+thing  141 n -   20 "MacGuffin/beggar"		BEGR
+thing  199 n -   20 "Oracle"			ORCL
+
+thing    9 f -   20 "Rebel"			HMN1
+thing   64 f -   20 "Macil (unkillable)"	LEDR
+thing  200 f -   20 "Macil (killable)"		LEAD
+thing   66 f -   20 "Advisor"			PEAS # Grey
+thing   67 f -   20 "Person"			PEAS # Brown
+thing   74 f -   20 "Gerard"			MRBD # Beige ?
+thing  134 f -   20 "Macil's advisor"		PEAS # Grey
+thing  135 f -   20 "Advisor"			PEAS # Grey
+thing  136 f -   20 "Person"			PEAS # Brown
+thing  144 f -   20 "Rebel (operator?)"		HMN1
+thing  145 f -   20 "Rebel"			HMN1
+thing  150 f -   20 "Rebel"			HMN1
+
+thing    1 p -   16 "Player 1 start"		PLAYA1
+thing    2 p -   16 "Player 2 start"		PLAYB1
+thing    3 p -   16 "Player 3 start"		PLAYC1
+thing    4 p -   16 "Player 4 start"		PLAYD1
+thing   11 p -   16 "Deathmatch start"		PLAYF1
+thing   14 p -   16 "Teleport exit"		TFOG
+
+#thing widths below are guesses  --mattm
+thing   69 t -   16 "Level-change marker"	PLAYA5
+thing  118 t -   16 "Scoot spot 1"		PLAYE1
+thing  119 t -   16 "Scoot spot 2"		PLAYE2
+thing  120 t -   16 "Scoot spot 3"		PLAYE3
+thing  121 t -   16 "Scoot spot 4"		PLAYE4
+thing  122 t -   16 "Scoot spot 5"		PLAYE5
+thing  123 t -   16 "Scoot spot 6"		PLAYE6
+thing  124 t -   16 "Scoot spot 7"		PLAYE7
+thing  125 t -   16 "Scoot spot 8"		PLAYE8
+
+thing 2001 w -   16 "Cross bow"			CBOW
+thing 2002 w -   16 "Assault gun"		RIFL
+thing 2003 w -   16 "Mini-missile launcher"	MMSL
+thing 2005 w -   16 "Flame thrower"		FLAM
+thing  154 w -   16 "Grenade launcher"		GRND
+thing 2004 w -   16 "Mauler"			TRPD
+thing 2006 w -   16 "Pulse rifle"		RIFLB0
+thing   81 w -   17 "Sigil (assembled)"		SIGLE0
+
+thing 2007 a -   16 "Clip of bullets"		BLIT
+thing 2048 a -   16 "Ammo"			BBOX
+thing  115 a -   16 "Poison bolts"		PQRL
+thing  114 a -   16 "Electric bolts"		XQRL
+thing  152 a -   16 "He-grenade rounds"		GRN1
+thing  153 a -   16 "Phosphorous grenades"	GRN2
+thing 2010 a -   16 "Rocket"			MSSL
+thing 2046 a -   16 "Box of rockets"		ROKT
+thing 2047 a -   16 "Energy pod"		BRY1 #ok
+#thing widths below are guesses  --mattm
+thing   17 a -   16 "Energy pack"		CPAC
+
+thing  138 b -   17 "10 gold"			CRED
+thing   10 b -   17 "Teleporter beacon"		BEAC
+thing  207 b -   20 "Targeter"			TARG
+thing 2025 b -   20 "Environmental suit"	MASK
+thing 2026 b -   17 "Map"			PMAP
+
+#Thing widths below are guesses  --mattm
+thing   59 k -   20 "Degnin ore"		XPRK
+thing  205 k -   20 "Chalice"			RELC
+thing  220 k -   20 "The Front's coupling"	COUPA0
+thing  226 k -   20 "Junked coupling"		COUPC0
+thing   52 k -   20 "Officer's uniform"		OFIC
+
+#thing widths below are guesses  --mattm
+thing  113 c -   16 "Preserved hearts"		HERT
+thing  213 c -   16 "Preserved spine"		TNK4
+thing  229 c -   16 "Preserved brain"		TNK6
+thing  201 c -   16 "Partial Acolyte"		ARMR
+#sprites below are *also* guesses, but they look similar anyway
+thing  209 c -   20 "Tank of bodies 1"		TNK1
+thing  210 c -   20 "Tank of bodies 2"		TNK2
+thing  211 c -   20 "Tank of bodies 3"		TNK3
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ygd/strife10.ygd	Wed Sep 21 04:30:44 2011 +0300
@@ -0,0 +1,418 @@
+# Yadex game definition file version 4
+#
+#	strife.ygd
+#	Yadex Game Definitions for Strife 1.0
+#	AYM 1999-02-27
+#	mattm 2000.05.05 05.29
+#
+
+# FIXME this file contains many inaccuracies and
+# errors ;
+# - most things types are missing
+# - most new (w.r.t. Doom) linedef types are
+#   missing.
+# - some redefined (w.r.t. Doom) linedef types
+#   still have the Doom definition.
+# - some sector types may be missing (or wrong).
+# Anyone who knows Strife want to fix it ?
+
+level_format    doom
+level_name      map01
+picture_format  normal
+sky_flat        f_sky001
+texture_format  normal
+texture_lumps   normal
+
+#
+#	Definition of linedef type groups
+#	Format is : ldtgroup <ldtgroup> <description>
+#
+
+ldtgroup d "Door"
+ldtgroup r "Door (red key)"
+ldtgroup y "Door (yellow key)"
+ldtgroup b "Door (blue key)"
+ldtgroup D "Door (turbo)"
+ldtgroup a "Door (animated)"
+ldtgroup l "Lift"
+ldtgroup F "Floor (raise)"
+ldtgroup f "Floor (lower)"
+ldtgroup c "Ceiling"
+ldtgroup C "Crushing ceiling"
+ldtgroup t "Teleport"
+ldtgroup L "Light"
+ldtgroup e "End level"
+ldtgroup m "Moving floor"
+ldtgroup s "Raising stairs"
+#ldtgroup B "Force fields"
+ldtgroup x "Misc."
+
+#
+#	Definition of linedef types
+#	Format is : ldt <number> <ldtgroup> <shortdesc> <longdesc>
+#	<shortdesc> must not exceed 16 characters.
+#
+
+ldt   0 x "-- Normal"        "--  Normal"
+ldt   1 d "DR Open door"     "DR  Open  door"
+ldt   2 d "W1 Open door (O)" "W1  Open  door (stays open)"
+ldt   3 d "W1 Close door"    "W1  Close door"
+ldt   4 d "W1 Open door"     "W1  Open  door"
+ldt   5 F "W1 Floor up LIC"  "W1  Raise floor to LIC"
+ldt   6 C "W1 Crush FF"      "W1  Start fast crushing, fast hurt"
+ldt   7 s "S1 Raise stairs"  "S1  Raise stairs (several sectors 0/999)"
+ldt   8 s "W1 Raise stairs"  "W1  Raise stairs (several sectors 0/999)"
+ldt   9 x "S1 Donut"         "S1  Lower floor, raise Ne. floor (NXP) 'Donut'"
+ldt  10 l "W1 Lower lift"    "W1  Lower lift"
+ldt  11 e "S- End level"     "S-  End level, go to next level"
+ldt  12 L "W1 Light to HE"   "W1  Light level goes to HE"
+ldt  13 L "W1 Light to 255"  "W1  Light level goes to 255"
+ldt  14 F "S1& F. up 32 TX"  "S1& Raise floor by 32 (TX)"
+ldt  15 F "S1& F. up 24 TX"  "S1& Raise floor by 24 (TX)"
+ldt  16 d "W1 Close for 30s" "W1  Close door for 30 seconds"
+ldt  17 L "W1 Start blink"   "W1  Start blinking lights"
+ldt  18 F "S1 Floor up nhEF" "S1  Raise floor to nhEF"
+ldt  19 f "W1 Floor dn HEF"  "W1  Lower floor to HEF"
+ldt  20 F "S1& F up nhEF TX" "S1& Raise floor to nhEF (TX)"
+ldt  21 l "S1 Lower lift"    "S1  Lower lift"
+ldt  22 F "W1& F up nhEF TX" "W1& Raise floor to nhEF (TX)"
+ldt  23 f "S1 Floor dn LEF"  "S1  Lower floor to LEF"
+ldt  24 F "G1 Floor up LIC"  "G1  Raise floor to LIC"
+ldt  25 C "W1 Crush FS"      "W1  Start fast crushing, slow hurt"
+ldt  26 b "DR Open blue dr"  "DR  Open  door, blue key"
+ldt  27 y "DR Open yel dr"   "DR  Open  door, yellow key"
+ldt  28 r "DR Open red dr"   "DR  Open  door, red key"
+ldt  29 d "S1 Open door"     "S1  Open  door"
+ldt  30 F "W1 Floor up SLT"  "W1  Raise floor by ShortestLowerTexture"
+ldt  31 d "D1 Open door (O)" "D1  Open  door (stays open)"
+ldt  32 b "D1 Open blu (O)"  "D1  Open  door (stays open), blue key"
+ldt  33 r "D1 Open red (O)"  "D1  Open  door (stays open), red key"
+ldt  34 y "D1 Open yel (O)"  "D1  Open  door (stays open), yellow key"
+ldt  35 L "W1 Light to 35"   "W1  Light level goes to 35"
+ldt  36 f "W1 F. DN HEF+8"   "W1  Lower turbo floor to HEF + 8"
+ldt  37 f "W1 F. dn LEF NXP" "W1  Lower floor to LEF (NXP)"
+ldt  38 f "W1 Floor dn LEF"  "W1  Lower floor to LEF"
+ldt  39 t "W1 Teleport"      "W1  Teleport to another sector"
+ldt  40 c "W1 Ceil up HEC"   "W1  Raise ceiling to HEC"
+ldt  41 c "S1 Ceil dn floor" "S1  Lower ceiling to floor"
+ldt  42 d "SR Close door"    "SR  Close door"
+ldt  43 c "SR Ceil dn floor" "SR  Lower ceiling to floor"
+ldt  44 c "W1 Ceil dn flr+8" "W1  Lower ceiling to floor + 8"
+ldt  45 f "SR Floor dn HEF"  "SR  Lower floor to HEF"
+ldt  46 d "GR Open door (O)" "GR  Open  door (stays open)"
+ldt  47 F "G1 F. up nhEF TX" "G1  Raise floor to nhEF (TX)"
+ldt  48 x "-- Scroll left"   "--  Animated wall (scrolls leftward)"
+ldt  49 c "S1 Ceil dn flr+8" "S1  Lower ceiling to floor + 8"
+ldt  50 d "S1 Close door"    "S1  Close door"
+ldt  51 e "S- Secret level"  "S-  End level, go to secret level"
+ldt  52 e "W- End level"     "W-  End level, go to next level"
+ldt  53 m "W1 Start moving"  "W1  Start moving floor"
+ldt  54 m "W1 Stop moving f" "W1  Stop  moving floor"
+ldt  55 F "S1 F. up LIC-8"   "S1  Raise floor to LIC - 8, crush"
+ldt  56 F "W1& F. up LIC-8"  "W1& Raise floor to LIC - 8, crush"
+ldt  57 C "W1& Stop crush"   "W1& Stop  crushing"
+ldt  58 F "W1 Floor up 24"   "W1  Raise floor by 24"
+ldt  59 F "W1 F. up 24 TXP"  "W1  Raise floor by 24 (TXP)"
+ldt  60 f "SR Floor dn LEF"  "SR  Lower floor to LEF"
+ldt  61 d "SR Open door (O)" "SR  Open  door (stays open)"
+ldt  62 l "SR Lower lift"    "SR  Lower lift"
+ldt  63 d "SR Open door"     "SR  Open  door"
+ldt  64 F "SR Floor up LIC"  "SR  Raise floor to LIC"
+ldt  65 F "SR F. up LIC-8"   "SR  Raise floor to LIC - 8, crush"
+ldt  66 F "SR& F. up 24 TX"  "SR& Raise floor by 24 (TX)"
+ldt  67 F "SR& F. up 32 TX"  "SR& Raise floor by 32 (TX)"
+ldt  68 f "SR& F up nhEF TX" "SR& Raise floor to nhEF (TX)"
+ldt  69 F "SR F. up nhEF"    "SR  Raise floor to nhEF"
+ldt  70 f "SR F. DN HEF+8"   "SR  Lower turbo floor to HEF + 8"
+ldt  71 f "S1 F. DN HEF+8"   "S1  Lower turbo floor to HEF + 8"
+ldt  72 c "WR Ceil dn flr+8" "WR  Lower ceiling to floor + 8"
+ldt  73 C "WR& Crush SS"     "WR& Start slow crushing, slow hurt"
+ldt  74 C "WR& Stop crush"   "WR& Stop  crushing"
+ldt  75 d "WR Close door"    "WR  Close door"
+ldt  76 d "WR Close for 30s" "WR  Close door for 30 seconds"
+ldt  77 C "WR& Crush FF"     "WR& Start fast crushing, fast hurt"
+#ldt 78 x "-- Unimplemented" "--  Unimplemented"
+ldt  79 L "WR Light to 35"   "WR  Light level goes to 35"
+ldt  80 L "WR Light to HE"   "WR  Light level goes to HE"
+ldt  81 L "WR Light to 255"  "WR  Light level goes to 255"
+ldt  82 f "WR Floor dn LEF"  "WR  Lower floor to LEF"
+ldt  83 f "WR Floor dn HEF"  "WR  Lower floor to HEF"
+ldt  84 f "WR F. dn LEF NXP" "WR  Lower floor to LEF (NXP)"
+#ldt 85 x "-- Unimplemented" "--  Unimplemented"
+ldt  86 d "WR Open door (O)" "WR  Open  door (stays open)"
+ldt  87 m "WR& Start moving" "WR& Start moving floor"
+ldt  88 l "WR Lower lift"    "WR  Lower lift"
+ldt  89 m "WR& Stop moving"  "WR& Stop  moving floor"
+ldt  90 d "WR Open door"     "WR  Open  door"
+ldt  91 F "WR Floor up LIC"  "WR  Raise floor to LIC"
+ldt  92 F "WR Floor up 24"   "WR  Raise floor by 24"
+ldt  93 F "WR F. up 24 TXP"  "WR  Raise floor by 24 (TXP)"
+ldt  94 F "WR F. up LIC-8"   "WR  Raise floor to LIC - 8, crush"
+ldt  95 F "WR F. up nhEF TX" "WR  Raise floor to nhEF (TX)"
+ldt  96 F "WR Floor up SLT"  "WR  Raise floor by ShortestLowerTexture"
+ldt  97 t "WR Teleport"      "WR  Teleport to another sector"
+ldt  98 f "WR F. DN HEF+8"   "WR  Lower turbo floor to HEF + 8"
+ldt  99 b "SR OPEN blu door" "SR  Open  turbo door, blue key [v1.6]"
+ldt 100 s "W1 RaiseStairs16" "W1  Raise stairs (step=16), crush [v1.6]"
+ldt 101 F "S1 Floor up LIC"  "S1  Raise floor to LIC"
+ldt 102 f "S1 Floor dn HEF"  "S1  Lower floor to HEF"
+ldt 103 d "S1 Open door (O)" "S1  Open  door (stays open)"
+ldt 104 L "W1 Light to LE"   "W1  Light level goes to LE"
+ldt 105 D "WR OPEN door"     "WR  Open  turbo door [v1.6]"
+ldt 106 D "WR OPEN door (O)" "WR  Open  turbo door (stays open) [v1.6]"
+ldt 107 D "WR CLOSE door"    "WR  Close turbo door [v1.6]"
+ldt 108 D "W1 OPEN door"     "W1  Open  turbo door [v1.6]"
+ldt 109 D "W1 OPEN door (O)" "W1  Open  turbo door (stays open) [v1.6]"
+ldt 110 D "W1 CLOSE door"    "W1  Close turbo door [v1.6]"
+ldt 111 D "S1 OPEN door"     "S1  Open  turbo door [v1.6]"
+ldt 112 D "S1 OPEN door (O)" "S1  Open  turbo door (stays open) [v1.6]"
+ldt 113 D "S1 CLOSE door"    "S1  Close turbo door [v1.6]"
+ldt 114 D "SR OPEN door"     "SR  Open  turbo door [v1.6]"
+ldt 115 D "SR OPEN door (O)" "SR  Open  turbo door (stays open) [v1.6]"
+ldt 116 D "SR CLOSE door"    "SR  Close turbo door [v1.6]"
+ldt 117 D "DR OPEN door"     "DR  Open  turbo door [v1.6]"
+ldt 118 D "D1 OPEN door (O)" "D1  Open  turbo door (stays open) [v1.6]"
+ldt 119 F "W1 Floor up nhEF" "W1  Raise floor to nhEF [v1.6]"
+ldt 120 l "WR LOWER lift"    "WR  Lower turbo lift [v1.6]"
+ldt 121 l "W1 LOWER lift"    "W1  Lower turbo lift [v1.6]"
+ldt 122 l "S1 LOWER lift"    "S1  Lower turbo lift [v1.6]"
+ldt 123 l "SR LOWER lift"    "SR  Lower turbo lift [v1.6]"
+ldt 124 e "W- Secret level"  "W-  End level, go to secret level [v1.6]"
+ldt 125 t "W1 Teleport mons" "W1  Teleport monsters only [v1.6]"
+ldt 126 t "WR Teleport mons" "WR  Teleport monsters only [v1.6]"
+ldt 127 s "S1 RaiseStairs16" "S1  Raise stairs (step=16), crush [v1.6]"
+ldt 128 F "WR Floor up nhEF" "WR  Raise floor to nhEF [v1.6]"
+ldt 129 F "WR Floor UP nhEF" "WR  Raise turbo floor to nhEF [v1.6]"
+ldt 130 F "W1 Floor UP nhEF" "W1  Raise turbo floor to nhEF [v1.6]"
+ldt 131 F "S1 Floor UP nhEF" "S1  Raise turbo floor to nhEF [v1.6]"
+ldt 132 F "SR Floor UP nhEF" "SR  Raise turbo floor to nhEF [v1.6]"
+ldt 133 b "S1 OPEN blu door" "S1  Open  turbo door, blue key [v1.6]"
+ldt 134 r "SR OPEN red door" "SR  Open  turbo door, red key [v1.6]"
+ldt 135 r "S1 OPEN red door" "S1  Open  turbo door, red key [v1.6]"
+ldt 136 y "SR OPEN yel door" "SR  Open  turbo door, yellow key [v1.6]"
+ldt 137 y "S1 OPEN yel door" "S1  Open  turbo door, yellow key [v1.6]"
+ldt 138 L "SR Light to 255"  "SR  Light level goes to 255 [v1.6]"
+ldt 139 L "SR Light to 0"    "SR  Light level goes to 0 [v1.6]"
+ldt 140 F "S1 Floor up 512"  "S1  Raise floor by 512, medium speed [v1.6]"
+ldt 141 C "W1& Crush SS sil" "W1& Start slow crushing, slow hurt, silent [v1.6]"
+ldt 143 x "-- Scroll down"   "--  Animated wall (scrolls downward)"
+ldt 144 a "XR Open animated" "XR  Open animated door"
+ldt 147 x "S1 Deac. FField"  "S1  Deactivate force field"
+ldt 148 x "-- Force Field"   "--  Force field, attempting to 'use' hurts"
+ldt 150 x "WR Sound alarms"  "WR  Sound alarms; alert Acolytes, Templars, etc"
+ldt 155 l "SR Raise lift"    "SR  Raise lift"
+ldt 165 x "-- Doesn't work"  "--  Print 'That doesn't seem to work' message"
+ldt 182 x "G1 Smashable"     "--  Smashable"
+ldt 185 t "W? STport ?"      "W?  Silent teleport <?>"
+ldt 195 t "W? STport, Aco."  "W?  Silent teleport <?>, become dummy Acolyte"
+ldt 205 x "SR 'Reg. only'"   "SR  Print 'registered version only' message"
+
+#
+#	Definition of sector types
+#	Format is : st <number> <shortdesc> <longdesc>
+#	<shortdesc> must not exceed 14 characters.
+#
+
+st  0 "X Normal"       "X Normal"
+st  1 "  Blinks rand"  "  Light blinks randomly"
+st  2 "  Flashes 2 Hz" "  Light flashes 2 Hz"
+st  3 "  Flashes 1 Hz" "  Light flashes 1 Hz"
+st  4 "P -20% & 2Hz"   "P -10/20% health, flashes 2 Hz"
+st  5 "P -10% health"  "P -5/10% health"
+st  7 "P -5% health"   "P -2/5% health"
+st  8 "  Oscillates"   "  Light oscillates"
+st  9 "P Secret"       "P Secret"
+st 10 "  Closes 30 s"  "  30 s after level start, ceiling closes like a door"
+st 11 "P -20% & end"   "P -10/20% health and end level when health <= 10%"
+st 12 "  Flash1Hz syn" "  Light flashes 1 Hz, synchronized"
+st 13 "  Flash2Hz syn" "  Light flashes 2 Hz, synchronized"
+st 14 "  Opens 300 s"  "  300 s after level start, ceiling opens like a door"
+st 15 "  Instant kill" "  Things standing on the sector are killed instantly"
+st 16 "P -20% health"  "P -10/20% health"
+st 17 "  Flicker rand" "  Light flickers on and off randomly [v1.6]"
+st 18 "  Push objects" "  Push objects (speed and angle depend on tag)"
+
+#
+#	Definition of thing groups
+#	Format is : thinggroup <thinggroup> <colour> <description>
+#
+
+thinggroup p rgb:0/f/0 "Player"
+thinggroup f rgb:0/b/0 "Friend"
+thinggroup e rgb:f/0/0 "Enemy"
+#thinggroup E rgb:f/8/8 "Enemy w/key"
+thinggroup n rgb:d/d/0 "Other character"
+thinggroup h rgb:2/8/0 "Health & armour"
+thinggroup w rgb:f/a/0 "Weapon"
+thinggroup a rgb:8/5/0 "Ammunition"
+thinggroup b rgb:2/8/0 "Misc. bonus"
+thinggroup k rgb:f/0/f "Key/trinket"
+thinggroup t rgb:0/a/0 "Cross-map teleport"
+#thinggroup s rgb:0/b/d "Special"
+thinggroup d rgb:6/6/c "Decoration"
+thinggroup l rgb:6/6/c "Lighting"
+thinggroup c rgb:6/6/c "Corpse"
+
+#
+#	Definition of things
+#	Format is : thing <number> <thinggroup> <flags> <radius> <description>
+#	<description> must not exceed 19 characters  --mattm
+#
+
+thing   22 d -   10 "Crusader wreck"		ROB2P
+thing   24 d -   10 "Siren"			KLAX
+thing   33 d -   16 "Dead tree"			TRE1
+thing   44 d -   16 "Statue"			STAT
+thing   46 d -   17 "Lantern"			LANT
+thing   48 d -   16 "Electrical column"		MONI
+thing   50 d -   17 "Torch on a stand"		LOGS
+thing   51 d -   16 "Palm tree"			TREEA
+thing   60 d -   10 "Small shrub"		BUSH
+thing   62 d -   10 "Shrub"			SHRB
+thing   82 d -   10 "Wood barrel"		BARW
+thing   94 d -   10 "Barrel"			BART
+thing  112 d -   10 "Fountain"			WTFT
+thing  165 d -   10 "Mug"			MUGG
+thing  194 d -   20 "Anvil"			ANVL
+thing  202 d -   16 "Tree"			TREEB
+thing  215 d -   16 "Wood in water"		LOGG
+#thing widths below are guesses  --mattm
+# Mine are even worse: they're just random. --AYM
+thing   23 d -   32 "Teleporter marker"		TELP
+thing   70 d -   16 "Flaming barrel?"		BARL
+thing  103 d -    4 "Dripping water pt 1?"	DRIPC
+thing   53 d -    4 "Dripping water pt 2?"	DRIPC
+thing  204 d -   16 "Holographic monk"		NEAL
+thing  208 d -   16 "Gun range target"		HOGN
+thing   85 d -   12 "Rat"			RATTB2B8
+thing  189 d -   16 "Three-Legged stool"	STOL
+thing  117 d -   16 "Medical device"		CRAB
+
+thing 2011 h -   20 "Med patch"			STMP
+thing 2012 h -   20 "Medical kit"		MDKT
+thing 2018 h -   17 "Leather armor"		ARM2
+thing 2019 h -   17 "Metal armor"		ARM1
+thing 2024 h -   20 "Shadow armor"		SHD1
+
+thing   34 l -   16 "Candle"			CNDL
+thing   95 l -    8 "Grey FT lamp"		LITS
+thing  107 l -    8 "Wall torch"		TRCH
+#thing widths below are guesses  --mattm
+thing  225 l -   16 "Alien lamp"		SPDL
+thing  106 l -   16 "Brazier"			BRAZ
+thing  105 l -   16 "Bowl with fire"		BOWL
+
+thing   58 e -   20 "Beige Acolyte"		AGRD
+thing  147 e -   20 "Green Acolyte"		AGRD
+thing  148 e -   20 "Acolyte (red ?)"		AGRD
+thing 3002 e -   20 "Beige Acolyte"		AGRD
+thing  143 e -   20 "Brown Acolyte"		AGRD
+#thing widths below are guesses  --mattm
+thing  146 e -   20 "Aggressive Acolyte"	AGRDF8
+thing  142 e -   20 "Acolyte w/key"		AGRD
+thing  186 e -   16 "Stalker"			SPIDJ #1st rightsideup --mattm
+thing 3006 e -   20 "Sentinel"			SEWRC1
+thing 3003 e -   20 "Templar"			PGRD
+thing 3001 e -   20 "Reaver"			ROB1
+thing 3005 e -   24 "Crusader"			ROB2
+thing   16 e -   32 "Inquisitor"		ROB3
+thing   71 e -   20 "Programmer?"		PRGRH0
+thing  187 e -   20 "Bishop?"			MLDR
+thing   76 e -   20 "Oracle's specter"		ALN1
+thing   12 e -   20 "Loremaster"		PRST
+thing   26 e -   20 "Entity nest? (pod?)"       NEST
+thing  198 e -   20 "Entity pod? (nest?)"       PODD
+thing   27 e -   17 "Turret"			TURT
+
+thing   72 n -   16 "Bar keeper"		MRBD # Brownish, sandy brown
+thing   73 n -   16 "Armourer"			MRBD # Nat, nat
+thing  116 n -   16 "Bowyer/Feris"		MRBD # Green, black
+thing   65 n -   20 "Harris"			PEAS # Red
+thing  130 n -   20 "Peasant (greenish beige)"	PEAS # Greenish beige
+thing  132 n -   20 "Harris"			PEAS # Red
+thing  137 n -   20 "Peasant (brown)"		PEAS # Brown
+thing  169 n -   20 "Spawned peasant"		PEAS # Red
+thing  170 n -   20 "Peasant spawner"		PEAS # Red
+thing  173 n -   20 "Peasant (green)"		PEAS # Green
+thing  181 n -   20 "Governor Mourel"		PEAS # Cyan
+thing 3004 n -   20 "Peasant (greenish beige)"	PEAS # Greenish beige
+thing  172 n -   20 "Richter"			PEAS # Dark green
+#Thing widths below are guesses  --mattm
+thing  141 n -   20 "MacGuffin/beggar"		BEGR
+thing  199 n -   20 "Oracle"			ORCL
+
+thing    9 f -   20 "Rebel"			HMN1
+thing   64 f -   20 "Macil (unkillable)"	LEDR
+thing  200 f -   20 "Macil (killable)"		LEAD
+thing   66 f -   20 "Advisor"			PEAS # Grey
+thing   67 f -   20 "Person"			PEAS # Brown
+thing   74 f -   20 "Gerard"			MRBD # Beige ?
+thing  134 f -   20 "Macil's advisor"		PEAS # Grey
+thing  135 f -   20 "Advisor"			PEAS # Grey
+thing  136 f -   20 "Person"			PEAS # Brown
+thing  144 f -   20 "Rebel (operator?)"		HMN1
+thing  145 f -   20 "Rebel"			HMN1
+thing  150 f -   20 "Rebel"			HMN1
+
+thing    1 p -   16 "Player 1 start"		PLAYA1
+thing    2 p -   16 "Player 2 start"		PLAYB1
+thing    3 p -   16 "Player 3 start"		PLAYC1
+thing    4 p -   16 "Player 4 start"		PLAYD1
+thing   11 p -   16 "Deathmatch start"		PLAYF1
+thing   14 p -   16 "Teleport exit"		TFOG
+
+#thing widths below are guesses  --mattm
+thing   69 t -   16 "Level-change marker"	PLAYA5
+thing  118 t -   16 "Scoot spot 1"		PLAYE1
+thing  119 t -   16 "Scoot spot 2"		PLAYE2
+thing  120 t -   16 "Scoot spot 3"		PLAYE3
+thing  121 t -   16 "Scoot spot 4"		PLAYE4
+thing  122 t -   16 "Scoot spot 5"		PLAYE5
+thing  123 t -   16 "Scoot spot 6"		PLAYE6
+thing  124 t -   16 "Scoot spot 7"		PLAYE7
+thing  125 t -   16 "Scoot spot 8"		PLAYE8
+
+thing 2001 w -   16 "Cross bow"			CBOW
+thing 2002 w -   16 "Assault gun"		RIFL
+thing 2003 w -   16 "Mini-missile launcher"	MMSL
+thing 2005 w -   16 "Flame thrower"		FLAM
+thing  154 w -   16 "Grenade launcher"		GRND
+thing 2004 w -   16 "Mauler"			TRPD
+thing 2006 w -   16 "Pulse rifle"		RIFLB0
+thing   81 w -   17 "Sigil (assembled)"		SIGLE0
+
+thing 2007 a -   16 "Clip of bullets"		BLIT
+thing 2048 a -   16 "Ammo"			BBOX
+thing  115 a -   16 "Poison bolts"		PQRL
+thing  114 a -   16 "Electric bolts"		XQRL
+thing  152 a -   16 "He-grenade rounds"		GRN1
+thing  153 a -   16 "Phosphorous grenades"	GRN2
+thing 2010 a -   16 "Rocket"			MSSL
+thing 2046 a -   16 "Box of rockets"		ROKT
+thing 2047 a -   16 "Energy pod"		BRY1 #ok
+#thing widths below are guesses  --mattm
+thing   17 a -   16 "Energy pack"		CPAC
+
+thing  138 b -   17 "10 gold"			CRED
+thing   10 b -   17 "Teleporter beacon"		BEAC
+thing  207 b -   20 "Targeter"			TARG
+thing 2025 b -   20 "Environmental suit"	MASK
+thing 2026 b -   17 "Map"			PMAP
+
+#Thing widths below are guesses  --mattm
+thing   59 k -   20 "Degnin ore"		XPRK
+thing  205 k -   20 "Chalice"			RELC
+thing  220 k -   20 "The Front's coupling"      COUPA0
+thing  226 k -   20 "Junked coupling"		COUPC0
+thing   52 k -   20 "Officer's uniform"		OFIC
+
+#thing widths below are guesses  --mattm
+thing  113 c -   16 "Preserved hearts"		HERT
+thing  213 c -   16 "Preserved spine"		TNK4
+thing  229 c -   16 "Preserved brain"		TNK6
+thing  201 c -   16 "Partial Acolyte"		ARMR
+#sprites below are *also* guesses, but they look similar anyway
+thing  209 c -   20 "Tank of bodies 1"		TNK1
+thing  210 c -   20 "Tank of bodies 2"		TNK2
+thing  211 c -   20 "Tank of bodies 3"		TNK3
+