// Program written by Maarten Meuris AKA Nyerguds
program dune_edit;
uses crt, dos, math, sysutils;

TYPE
   // Input key codes - "endk" is the [END] key
   keymapper = Record
      up, down, left, right, space, enter, esc, back, pgup, pgdn, home, endk, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12 :char;
   end;
   // For storing layout characters
   chset      = array [1..10] of byte;
   // For coordinates of layout frames
   coords     = array [1..4] of integer;
   // For storing a 4-byte value as booleans
   boollist   = array [0..31] of boolean;
   // For storing a 4-byte value as bytes
   // ALWAYS USE AS LITTLE-ENDIAN!!! The read & write methods convert it to correspond to the big-endian in the exe file
   fourbyte   = array [0..3] of byte;

   // For the editing description for each data type
   descr      = array [1..2] of string[36];
   // For the help description for each data type
   bigdescr   = array [1..7] of string[48];

   // Type designed for data types where the list index in the editor does not necessarily correspond to the internal value
   values = Record
      val:integer;
      txt:string[30];
   end;

   // Type for the data identification table
   option = Record
      typeid: Integer;
      text: String[23];
      helpid: integer;
   end;

   // Type for defining the different kinds of script lines in the const section (special action scripts for buildings/units)
   scriptvalues = Record
      val:integer;
      isEnd:boolean;
      hasArg:boolean;
      shortTxt:string[4];
      longTxt:string[30];
   end;

   // For storing a script line read from the exe (special action scripts for buildings/units)
   scriptLine = Record
      command: byte; // is actually just a tupel; never insert a value higher than $F!
      argument:integer; // 3 remaining tupels of Word: never insert a value higher than $FFF!
   end;

   // This has been put in specific types to have a single type for the unit/structure/etc. lists
   lev2Lst = array[0..800] of String;
   lev3Lst = array[0..100] of Option;

var
    // Game version / Which list is active / Level to return to after level #4
    gamever,level,prevlev:integer;

    // Option list lengths (calculated on init)
    // Only 0-4 are used so far, but I put the length on 32 to be safe.
    // This list must be at least as long as "mainList".
    optsListlengths:array[0..32] of integer;

    // Binary editing mode enabled / Hexadecimal display mode enabled
    binEd,HexDisplay:boolean;
    // File to edit
    exefile:file;
    // input
    keyread:char;
    // Error message when editing fails or cancels
    errormsg:String;
    // filename string
    gamenamestr:String;
    // complete file path string
    gamepathstr:String;
    // navigation & scrolling data for all levels
    select,scroll,maxdisplay,listlen:array [1..5] of integer;
    // Display lists to print on screen
    lev2List,lev4List:lev2Lst;
    lev3List:lev3Lst;
    lev3data:array [0..19] of String[20];

const
    // General info Strings
    editorname:string[14] = 'Dune II Editor';
    editorversion:string[10] = 'v1.18.2';
    editorversiondate:string[30] = 'September 11, 2010';
    editorauthor:string[8] = 'Nyerguds';
    editorauthoremail:string[20] = 'nyerguds@gmail.com';
    defnamestr:String[9] = 'DUNE2.EXE';
    rulesfileprefix:String[6] = 'rules-';
    rulesfileext:String[3] = 'ini';

    // Input key codes
    keymap:keymapper = ( up:    char(072); down:  char(080);
                         left:  char(075); right: char(077);
                         space: char(032); enter: char(013);
                         esc:   char(027); back:  char(008);
                         pgup:  char(073); pgdn:  char(081);
                         home:  char(071); endk:  char(079);
                         f1:    char(059); f2:    char(060);
                         f3:    char(061); f4:    char(062);
                         f5:    char(063); f6:    char(064);
                         f7:    char(065); f8:    char(066);
                         f9:    char(067); f10:   char(068);
                         f11:   char(133); f12:   char(134)
                       );

    // character codes for drawing frames.
    // The two types are Inactive (single line) and Active (double line) 
//{
    // DOS ASCII version
    framechar:array[1..2] of chset = (
                       // north-west corner, north-east corner, south-west corner, south-east corner
                       // Horizontal line, vertical line, T-shape, upside-down T-shape, arrow up, arrow down
                       // NWC  NEC  SWC  SEC  HOR  VER   T   UDT  AUP  ADN
                       //  |"  "|   |_   _|    -    |   "|"  _|_   ^    v
                         ($DA, $BF, $C0, $D9, $C4, $B3, $C2, $C1, $18, $19),  // inactive
                         ($C9, $BB, $C8, $BC, $CD, $BA, $CB, $CA, $18, $19)); // active
//}
{
    // pure UTF-8 version
    framechar:array[1..2] of chset = (
                         ($2E, $2E, $60, $27, $2D, $7C, $2D, $2D, $5E, $76),   // ('.', '.', '`', '''','-', '|', '-', '-', '^', 'v'),
                         ($2B, $2B, $2B, $2B, $3D, $23, $3D, $3D, $5E, $76));  // ('+', '+', '+', '+', '=', '#', '=', '=', '^', 'v'));
//}

    //color scheme
    // Selected item on active level
    activeitemcolor:byte = Yellow;
    activeitembgcolor:byte = LightRed;
    // nonselected item on active level
    activelevcolor:byte = white;
    activelevbgcolor:byte = Blue;
    // Selected item on inactive level
    inactiveitemcolor:byte = White;
    inactiveitembgcolor:byte = Black;
    // nonselected item on inactive level
    // these serve as general layout colors
    inactivelevcolor:byte = LightGray;
    inactivelevbgcolor:byte = Blue;

    // == LAYOUT CONTROL ==
    // Coordinates of layout frames
    selectBoundaries:array[1..5] of coords = (
                         ( 3, 4,25, 6), // level 1 list
                         ( 3, 9,25,23), // level 2 list
                         (30, 4,54,23), // level 3 list
                         (17,12,39,17), // level 4 list
                         (17,12,39,17)  // level 5 list
                         );
    selectionLengths:array[1..5] of integer = (23,23,25,33,33);

    // WARNING, NOT all of these are coordinates:
    // they are upper left corner X and Y, width, and height
    drawBoundaries:array[1..5] of coords = (
                         ( 1, 3,27, 5), // level 1 frame
                         ( 1, 8,27,17), // level 2 frame
                         (28, 3,53,22), // level 3 frame
                         (15, 5,52,15), // level 4 frame
                         (15, 5,52,15)  // level 5 frame
                         );
    secondcolumn:array[1..5] of integer = (-1,-1,29,-1,-1);
    secondcolumnSelection:integer=21;
    // == END OF LAYOUT CONTROL ==


    // == DUNE II VERSION CONTROL ==
    // When adding a version, all array lengths must be updated!

    // String to display for each version
    dunever:   array[0..5] of string[7] = ('DEMO','1.00','1.07-US','1.07-EU','1.07-HS', 'DEMO-KY');

    dunevername:array[0..5] of String[48] = (
     'Demo version',
     'United States v1.00',
     'United States v1.07',
     'European v1.07',
     'HitSquad v1.07',
     'Demo version from the Legend of Kyrandia CD');
  // [________________________________________________] = max length for each line
    duneverinfo:array[0..5] of bigdescr = (
    ('This version is the automatically playing demo','released on the Westwood FTP site.','Editing it is probably not very useful.','','','',''),
    ('The original English-only US release of Dune II.','','','','','',''),
    ('The updated version of the English-only US','release of Dune II. It fixes a number of bugs,','like the fact the Starport countdown could get','stuck on "T-minus 0".','','',''),
    ('The European release of Dune II, with','three languages: English, French and German.','It has all the bug fixes of the US 1.07 version.','','','',''),
    ('An alternate release of the European 3-language','version, with three languages: English, French','and German. It has all the bug fixes of the','US 1.07 version.','It is unknown if this is a later or earlier','version than the other EU one, but this one','misses the specific German font for the sidebar.'),
    ('This version has no ingame demo, but just loops','the game intro. Because of this, all the','undoubtedly magnificent edits you''re planning','to make have no significance at all.','','Go do something more productive.',''));

    // place of the identification string (gamenamestr) in each version
                                      // demo   1.00   1.07US 1.07EU 1.07HS demoky
    verAddress:array[0..5] of integer = (225278,229282,228274,229682,229586,228336);

    // Correction to make string offsets out of exe references for each version
                                       //     demo               1.00               1.07US             1.07EU             1.07HS           demo Kyrandia
    refAddress:array[0..5] of fourbyte = (($32,$4D,$90,$F0), ($33,$2B,$81,$10), ($32,$EC,$85,$00), ($33,$44,$7F,$80), ($33,$3E,$7F,$E0), ($33,$BB,$78,$10));

   // Correction to make script offsets out of exe references for each version
                                     // demo   1.00   1.07US 1.07EU 1.07HS demoky
    refHeader:array[0..5] of integer = ($4A00, $4C00, $4C00, $4C00, $4C00, $4C00);


    // Start offset of unit/struct/etc. data for each version
    typeOffset:array[-1..4] of array[0..5] of integer= (
                         // demo   1.00   1.07US 1.07EU 1.07HS demoky
                           (238896,243306,241990,244834,244726,246814), // movement types offsets
                           (201840,198480,195760,195840,195760,197712), // units offsets
                           (199930,196570,193930,194010,193930,195882), // structures offsets
                           (237898,242308,240988,243832,243724,245812), // houses offsets
                           (207822,204030,202062,202142,202062,204014), // actions offsets
                           (208000,204208,202240,202320,202240,204192)  // files offsets
                           );
    // Number of units, structures etc. for each version. Mostly added for the files though.
    typeListLen:array[-1..4] of array[0..5] of integer = (
                         // demo   1.00   1.07US 1.07EU 1.07HS demoky
                           (6     ,6     ,6     ,6     ,6     ,6     ), // movement types list length
                           (27    ,27    ,27    ,27    ,27    ,27    ), // units list length
                           (19    ,19    ,19    ,19    ,19    ,19    ), // structures list length
                           (6     ,6     ,6     ,6     ,6     ,6     ), // houses list length
                           (14    ,14    ,14    ,14    ,14    ,14    ), // actions offsets
                           (189   ,568   ,606   ,676   ,675   ,677   )  // files list length
                           );

    // == END VERSION-SPECIFIC CONTROLS ==

    // == LISTS CONTROL ==
    // When adding a list, all array lengths must be updated, including "typeOffset" and "typeListLen" above!
    // Main list - this array's size defines the length of the main list
    // Negative-index lists are there purely to get data from them.
    mainlist:array[-1..4] of String[20] = (
                                          'Movement types', // Not shown because MoveUp doesn't go below index 0 ;)
                                          'Units         ',
                                          'Structures    ',
                                          'Houses        ',
                                          'Actions       ',
                                          'Files         ');

    // REFERENCE OPTION: the position of the option in the list
    // which holds this type's name reference
    // Options which are only for references are added before current ones, as negative numbers
    refoption:array[-1..4] of integer = (
                                           0,  // movement types list name option
                                           1,  // units list name option
                                           1,  // structures list name option
                                           0,  // houses list name option
                                           1,  // actions list name option
                                           0   // files list name option
                                       );
    // Option lists for units/structs
    // Size needs to be adjusted with typeid:-1 values to correspond to the lev3Lst type.
    TypeOptsList:array[-1..4] of lev3Lst = (
    // movement types (on index -1; not shown on list)
          (
              (typeid: 03; text: 'Name string reference  '; helpid: 03),
              (typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),
              (typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),
              (typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),
              (typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),
              (typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),
              (typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),
              (typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),
              (typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),
              (typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),
              (typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),
              (typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),
              (typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),
              (typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),
              (typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),
              (typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),
              (typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),
              (typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),
              (typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),
              (typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),
              (typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00)
         ),
    // unitOptsList
         (
              (typeid: 02; text: 'Short name ID          '; helpid: 02),
              (typeid: 03; text: 'Name string reference  '; helpid: 03),
              (typeid: 02; text: 'Long name ID           '; helpid: 02),
              (typeid: 03; text: 'WSA filename string ref'; helpid: 03),
              (typeid: 12; text: 'Air unit shadow        '; helpid: 00),
              (typeid: 13; text: 'Unknown 005 (bit 2)    '; helpid: -1),
              (typeid: 14; text: 'Unknown 005 (bit 3)    '; helpid: -1),
              (typeid: 15; text: 'Unknown 005 (bit 4)    '; helpid: -1),
              (typeid: 16; text: 'Unknown 005 (bit 5)    '; helpid: -1),
              (typeid: 17; text: 'Worm camouflage        '; helpid: 00),
              (typeid: 18; text: 'Has a rotating turret  '; helpid: 00),
              (typeid: 19; text: 'Unknown 005 (bit 8)    '; helpid: -1),
              (typeid: 12; text: 'Pick up for repairs    '; helpid: 00),
              (typeid: 13; text: 'No death message       '; helpid: 00),
              (typeid: 14; text: 'TAB selects this unit  '; helpid: 00),
              (typeid: 15; text: 'Full CPU outside screen'; helpid: 19), // 'ForceScriptCycles' - relates to TacticalPos
              (typeid: 16; text: 'Can target air units   '; helpid: 00),
              (typeid: 17; text: 'Is a priority target   '; helpid: 32), // for all units: 0 in demo/1.00, 1 in 1.07 versions
              (typeid: 18; text: 'Unkn 006 bit 7 (unused)'; helpid: 00),
              (typeid: 19; text: 'Unkn 006 bit 8 (unused)'; helpid: 00),
              (typeid: 20; text: 'Infantry spawn chance  '; helpid: 13),
              (typeid: 02; text: 'Hit points             '; helpid: 00),
              (typeid: 02; text: 'Sight                  '; helpid: 00),
              (typeid: 24; text: 'Sidebar icon           '; helpid: 24),
              (typeid: 02; text: 'Cost                   '; helpid: 00),
              (typeid: 02; text: 'Build Time             '; helpid: 00),
              (typeid: 02; text: 'Tech level             '; helpid: 00),
              (typeid: 10; text: 'Prerequisites          '; helpid: 10),
              (typeid: 01; text: 'Build icon order       '; helpid: 17),
              (typeid: 01; text: 'Upgrades needed        '; helpid: 00),
              (typeid: 05; text: 'Sidebar command #1     '; helpid: 05),
              (typeid: 05; text: 'Sidebar command #2     '; helpid: 05),
              (typeid: 05; text: 'Sidebar command #3     '; helpid: 05),
              (typeid: 05; text: 'Sidebar command #4     '; helpid: 05),
              (typeid: 02; text: '(CHOAM status - unused)'; helpid: 00),
              (typeid: 01; text: 'Unknown 022            '; helpid: -1),
              (typeid: 02; text: 'AI build priority      '; helpid: -1),
              (typeid: 02; text: 'Threat level for AI    '; helpid: 33),
              (typeid: 04; text: 'Owner                  '; helpid: 04),
              (typeid: 02; text: 'Unit array range min   '; helpid: 34),
              (typeid: 02; text: 'Unit array range max   '; helpid: 34),
              (typeid: 12; text: 'Unknown 028 (bit 1)    '; helpid: -1),
              (typeid: 13; text: 'Explode on target      '; helpid: 00),
              (typeid: 14; text: 'Explode when dying     '; helpid: 00),
              (typeid: 15; text: 'Sonic Immunity         '; helpid: 00),
              (typeid: 16; text: 'Bumpy Movement         '; helpid: 00),
              (typeid: 17; text: 'Tracked crushing       '; helpid: 00),
              (typeid: 18; text: 'Has user control       '; helpid: 00),
              (typeid: 19; text: 'Stay on map (air units)'; helpid: 00),
              (typeid: 12; text: 'Unknown 029 (bit 1)    '; helpid: -1),
              (typeid: 13; text: 'Unknown 029 (bit 2)    '; helpid: -1),
              (typeid: 14; text: 'Fires Twice            '; helpid: 00),
              (typeid: 15; text: 'Sand impact (if weapon)'; helpid: 18), // only works if "Explode on target"=true and if "weapon ROF"=0
              (typeid: 16; text: 'Unknown 029 (bit 5)    '; helpid: -1), // enemies don't attack this?
              (typeid: 17; text: 'Unknown 029 (bit 6)    '; helpid: -1),
              (typeid: 18; text: 'Unknown 029 (bit 7)    '; helpid: -1),
              (typeid: 19; text: 'Unknown 029 (bit 8)    '; helpid: 00), // seems like a dodgy description - needs more research
              (typeid: 02; text: 'Unknown 030            '; helpid: -1),
              (typeid: 02; text: 'Unknown 031            '; helpid: -1), // related to AI building more or less of this unit?
              (typeid: 06; text: 'Movement type          '; helpid: 06),
              (typeid: 02; text: 'Move animation speed   '; helpid: 00),
              (typeid: 02; text: 'Speed                  '; helpid: 00),
              (typeid: 02; text: 'Turning speed          '; helpid: 00),
              (typeid: 24; text: 'Unit graphics          '; helpid: 24),
              (typeid: 24; text: 'Turret graphics        '; helpid: 24),
              (typeid: 05; text: 'Default AI command     '; helpid: 00),
              (typeid: 25; text: 'Unit display mode      '; helpid: 25),
              (typeid: 24; text: 'Death animation        '; helpid: 16),
              (typeid: 02; text: 'Weapon rate of fire    '; helpid: 00),
              (typeid: 02; text: 'Weapon range           '; helpid: 00),
              (typeid: 02; text: 'Weapon damage          '; helpid: 00),
              (typeid: 02; text: 'Special animation      '; helpid: 35), // see segra's unit scripts explanation
              (typeid: 07; text: 'Weapon type            '; helpid: 07),
              (typeid: 11; text: 'Weapon sound           '; helpid: 11),
              (typeid: -1; text: ''; helpid: 00), (typeid: -1; text: ''; helpid: 00),
              (typeid: -1; text: ''; helpid: 00), (typeid: -1; text: ''; helpid: 00),
              (typeid: -1; text: ''; helpid: 00), (typeid: -1; text: ''; helpid: 00),
              (typeid: -1; text: ''; helpid: 00), (typeid: -1; text: ''; helpid: 00),
              (typeid: -1; text: ''; helpid: 00), (typeid: -1; text: ''; helpid: 00),
              (typeid: -1; text: ''; helpid: 00), (typeid: -1; text: ''; helpid: 00),
              (typeid: -1; text: ''; helpid: 00), (typeid: -1; text: ''; helpid: 00),
              (typeid: -1; text: ''; helpid: 00), (typeid: -1; text: ''; helpid: 00),
              (typeid: -1; text: ''; helpid: 00), (typeid: -1; text: ''; helpid: 00),
              (typeid: -1; text: ''; helpid: 00), (typeid: -1; text: ''; helpid: 00),
              (typeid: -1; text: ''; helpid: 00), (typeid: -1; text: ''; helpid: 00),
              (typeid: -1; text: ''; helpid: 00), (typeid: -1; text: ''; helpid: 00),
              (typeid: -1; text: ''; helpid: 00), (typeid: -1; text: ''; helpid: 00),
              (typeid: -1; text: ''; helpid: 00)
         ),
    //structOptsList
         (
              (typeid: 02; text: 'Short name ID          '; helpid: 02),
              (typeid: 03; text: 'Name string reference  '; helpid: 03),
              (typeid: 02; text: 'Long name ID           '; helpid: 02),
              (typeid: 03; text: 'WSA filename string ref'; helpid: 03),
              (typeid: 12; text: 'Unknown 005a (bit 1)   '; helpid: -1),
              (typeid: 13; text: 'Construction screen    '; helpid: 00),
              (typeid: 14; text: 'Unknown 005a (bit 3)   '; helpid: -1),
              (typeid: 15; text: 'No concrete needed     '; helpid: 00),
              (typeid: 16; text: 'Can receive airdrops   '; helpid: 00),
              (typeid: 17; text: 'Unknown 005a (bit 6)   '; helpid: -1),
              (typeid: 18; text: 'Unknown 005a (bit 7)   '; helpid: -1),
              (typeid: 19; text: 'Can be captured        '; helpid: 00),
              (typeid: 01; text: 'Unknown 005b           '; helpid: -1),
              (typeid: 20; text: 'Inf spawn chance / cell'; helpid: 13),
              (typeid: 02; text: 'Hit points             '; helpid: 00),
              (typeid: 02; text: 'Sight                  '; helpid: 00),
              (typeid: 24; text: 'Sidebar icon           '; helpid: 24),
              (typeid: 02; text: 'Cost                   '; helpid: 00),
              (typeid: 02; text: 'Build Time             '; helpid: 00),
              (typeid: 02; text: 'Tech level             '; helpid: 00),
              (typeid: 10; text: 'Prerequisites          '; helpid: 10),
              (typeid: 01; text: 'Build icon order       '; helpid: 17),
              (typeid: 01; text: 'CY upgrades needed     '; helpid: 00),
              (typeid: 01; text: 'Unknown 016            '; helpid: -1),
              (typeid: 01; text: 'Unknown 017            '; helpid: -1),
              (typeid: 01; text: 'Unknown 018            '; helpid: -1),
              (typeid: 01; text: 'Unknown 019            '; helpid: -1),
              (typeid: 01; text: 'Unknown 020            '; helpid: -1),
              (typeid: 01; text: 'Unknown 021            '; helpid: -1),
              (typeid: 01; text: 'Unknown 022            '; helpid: -1),
              (typeid: 01; text: 'Unknown 023            '; helpid: -1),
              (typeid: 01; text: 'Unknown 023            '; helpid: -1),
              (typeid: 02; text: 'Structure ID           '; helpid: 00),
              (typeid: 02; text: 'Weapon damage          '; helpid: 00),
              (typeid: 02; text: 'Threat level for AI    '; helpid: 33),
              (typeid: 04; text: 'Owner                  '; helpid: 04),
              (typeid: 02; text: 'Unknown 029            '; helpid: -1),
              (typeid: 00; text: 'Units can enter        '; helpid: 00),
              (typeid: 02; text: 'Spice storage          '; helpid: 00),
              (typeid: 02; text: 'Power consumed         '; helpid: 00),
              (typeid: 08; text: 'Foundation size        '; helpid: 08),
              (typeid: 32; text: 'Structure graphics ID  '; helpid: 36),
              (typeid: 31; text: 'Anim: Normal           '; helpid: 31),
              (typeid: 31; text: 'Anim: Production busy  '; helpid: 31),
              (typeid: 31; text: 'Anim: Production ended '; helpid: 31),
              (typeid: 07; text: 'Construction optn #1   '; helpid: 12),
              (typeid: 07; text: 'Construction optn #2   '; helpid: 12),
              (typeid: 07; text: 'Construction optn #3   '; helpid: 12),
              (typeid: 07; text: 'Construction optn #4   '; helpid: 12),
              (typeid: 07; text: 'Construction optn #5   '; helpid: 12),
              (typeid: 07; text: 'Construction optn #6   '; helpid: 12),
              (typeid: 07; text: 'Construction optn #7   '; helpid: 12),
              (typeid: 07; text: 'Construction optn #8   '; helpid: 12),
              (typeid: 02; text: '1st upgrade tech level '; helpid: 15),
              (typeid: 02; text: '2nd upgrade tech level '; helpid: 15),
              (typeid: 02; text: '3rd upgrade tech level '; helpid: 15),
              (typeid: -1; text: ''; helpid: 00), (typeid: -1; text: ''; helpid: 00),
              (typeid: -1; text: ''; helpid: 00), (typeid: -1; text: ''; helpid: 00),
              (typeid: -1; text: ''; helpid: 00), (typeid: -1; text: ''; helpid: 00),
              (typeid: -1; text: ''; helpid: 00), (typeid: -1; text: ''; helpid: 00),
              (typeid: -1; text: ''; helpid: 00), (typeid: -1; text: ''; helpid: 00),
              (typeid: -1; text: ''; helpid: 00), (typeid: -1; text: ''; helpid: 00),
              (typeid: -1; text: ''; helpid: 00), (typeid: -1; text: ''; helpid: 00),
              (typeid: -1; text: ''; helpid: 00), (typeid: -1; text: ''; helpid: 00),
              (typeid: -1; text: ''; helpid: 00), (typeid: -1; text: ''; helpid: 00),
              (typeid: -1; text: ''; helpid: 00), (typeid: -1; text: ''; helpid: 00),
              (typeid: -1; text: ''; helpid: 00), (typeid: -1; text: ''; helpid: 00),
              (typeid: -1; text: ''; helpid: 00), (typeid: -1; text: ''; helpid: 00),
              (typeid: -1; text: ''; helpid: 00), (typeid: -1; text: ''; helpid: 00),
              (typeid: -1; text: ''; helpid: 00), (typeid: -1; text: ''; helpid: 00),
              (typeid: -1; text: ''; helpid: 00), (typeid: -1; text: ''; helpid: 00),
              (typeid: -1; text: ''; helpid: 00), (typeid: -1; text: ''; helpid: 00),
              (typeid: -1; text: ''; helpid: 00), (typeid: -1; text: ''; helpid: 00),
              (typeid: -1; text: ''; helpid: 00), (typeid: -1; text: ''; helpid: 00),
              (typeid: -1; text: ''; helpid: 00), (typeid: -1; text: ''; helpid: 00),
              (typeid: -1; text: ''; helpid: 00), (typeid: -1; text: ''; helpid: 00),
              (typeid: -1; text: ''; helpid: 00), (typeid: -1; text: ''; helpid: 00),
              (typeid: -1; text: ''; helpid: 00), (typeid: -1; text: ''; helpid: 00),
              (typeid: -1; text: ''; helpid: 00)
         ),
    // houseOptsList
         (
              (typeid: 03; text: 'Name string reference  '; helpid: 03),
              (typeid: 20; text: 'Weakness to deviation  '; helpid: 20),
              (typeid: 02; text: 'LemonFactor (?)        '; helpid: 00),
              (typeid: 09; text: 'Decay factor           '; helpid: 09),
              (typeid: 02; text: 'Radar color index      '; helpid: 14),
              (typeid: 02; text: 'Palace recharge time   '; helpid: 00),
              (typeid: 02; text: 'Frigate delay time     '; helpid: 00),
              (typeid: 22; text: 'Voice prefix letter    '; helpid: 22),
              (typeid: 23; text: 'Palace special ability '; helpid: 23),
              (typeid: 21; text: 'Win music              '; helpid: 21),
              (typeid: 21; text: 'Lose music             '; helpid: 21),
              (typeid: 21; text: 'Mentat music           '; helpid: 21),
              (typeid: 03; text: 'House voice reference  '; helpid: 03),
              (typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),
              (typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),
              (typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),
              (typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),
              (typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),
              (typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),
              (typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),
              (typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),
              (typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),
              (typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),
              (typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),
              (typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),
              (typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),
              (typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),
              (typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),
              (typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),
              (typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),
              (typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00)
         ),
    // actionOptsList
         (
              (typeid: 02; text: 'Unknown 001            '; helpid: -1),
              (typeid: 03; text: 'Name string reference  '; helpid: 03),
              (typeid: 26; text: 'Action interrupt mode  '; helpid: 26),
              (typeid: 27; text: 'Sidebar mode           '; helpid: 27),
              (typeid: 28; text: 'Response sound         '; helpid: 28),
              (typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),
              (typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),
              (typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),
              (typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),
              (typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),
              (typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),
              (typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),
              (typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),
              (typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),
              (typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),
              (typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),
              (typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),
              (typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),
              (typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),
              (typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),
              (typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),
              (typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),
              (typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),
              (typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),
              (typeid: -1; text: ''; helpid: 00)
         ),
    // fileOptsList
         (
              (typeid: 03; text: 'Filename string ref.   '; helpid: 03),
              (typeid: 02; text: 'PAK identifier?        '; helpid: -1), // related to PAK archives. Internal identifier?
              (typeid: 02; text: 'Unknown 006            '; helpid: -1),
              (typeid: 02; text: 'Unknown 008            '; helpid: -1),
              (typeid: 02; text: 'Unknown 00A            '; helpid: -1),
              (typeid: 02; text: 'Unknown 00C            '; helpid: -1),
              (typeid: 02; text: 'Unknown 00E            '; helpid: -1),
              (typeid: 29; text: 'Parent file            '; helpid: 29),
              (typeid: 01; text: 'Unknown 011            '; helpid: -1),
              (typeid: 30; text: 'File type              '; helpid: 30),
              (typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),
              (typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),
              (typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),
              (typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),
              (typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),
              (typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),
              (typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),
              (typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),
              (typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),
              (typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),
              (typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),
              (typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),
              (typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),
              (typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),
              (typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),
              (typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),
              (typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),
              (typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),(typeid: -1; text: ''; helpid: 00),
              (typeid: -1; text: ''; helpid: 00)
         )
    );

    optHelp:array[-1..40] of bigdescr = (
   //     [________________________________________________] = max length for each line
    {-1} ('','--==UNKNOWN OPTION==--','','If you find out what this does, please tell me!','','',''),
    {00} ('[No help for this item]','','','','','',''), // keep empty as default value
    {01} ('','','','','','',''),
    {02} ('The NAME ID is a value that refers to an index','in the game''s strings file (DUNE.ENG/GER/FRE).','','If you want to change them, you have to look','them up in the strings file.','',''),
    {03} ('STRING REFERENCES are internal references which','point to a zero-terminated string. The editor ','converts these values to normal file addresses.','','Be VERY careful when editing these; changing','name references can have disastrous results.','Both this editor and the game rely on these.'),
    {04} ('The OWNERSHIP value is a list of switches that','allow or deny specific Houses the right to build','this specific unit or structure.','','','',''),
    {05} ('The SIDEBAR COMMANDS allow players to give','instructions to units. Note that these command','buttons may show weird behaviour if they are on','a different place than they are meant to be.','','After a move or attack command is completed, the','fourth command is automatically executed.'),
    {06} ('The MOVEMENT TYPE determines a lot of the unit''s','behaviour on the battlefield. Each movement type','has its own unique characteristics, like how ','units on foot can be crushed by tracked units,','and slithering units can''t move on rock.','',''),
    {07} ('The WEAPON TYPE is the projectile the unit will','fire. Since all projectiles are units, all units','appear in the selection list. However, using','normal units as projectiles doesn''t work, since','units need to have a certain set of options','enabled to be seen as a weapon type.',''),
    {08} ('The FOUNDATION determines the amount of cells a','structure takes, and which shape they are in.','','Note that changing the foundations of the','Concrete Slabs can give very unexpected results.','',''),
    {09} ('This is a ''weakness factor'' that indicates how','much damage structures of this house take every','time the decay strikes.','','Internally, the game adds 1 to this value. This','means that ''0'' still does 1 damage, and ''-1''','disables the decay completely.'),
   //     [________________________________________________] = max length for each line
    {10} ('The PREREQUISITE structures are the structures a','player needs to have before he can build this','unit or structure.','','','',''),
    {11} ('SOUNDS are played when a unit attacks or when a','weapon is fired.','The sounds indicated with "VOC" have a .VOC file','that is played. The rest only give generated','sounds.','',''),
    {12} ('Choosing a CONSTRUCTION OPTION gives a structure','a unit to add to its production options list.','','','','',''),
    {13} ('When something is destroyed, this percentage','determines the chance that a soldier will spawn.','For structures, this system is used for each','separate cell occupied by the structure.','','The list only has rough values. You can use','[F3] or [F4] for more detailed editing.'),
    {14} ('The index on the color palette that will be used','as radar color for this House.','','','','',''),
    {15} ('UPGRADE TECH LEVEL: Determines at which tech','level this factory upgrade can first be done.','','Note that the tech level is not always the same','as the mission number; the game often shifts','the tech levels depending on which house you','are playing with.'),
    {16} ('The DEATH ANIMATION is a 3-frame animation that','sometimes plays when a unit is destroyed.','','Choose the first frame of the animation you want','to use, or choose index #000 (the mouse arrow)','to disable the death animation.',''),
    {17} ('The BUILD ICON ORDER value determines the place','this construction option will have in the build','list of the structure that produces it.','A higher value will put it higher in the list.','','The only exceptions are the Concrete Slabs,','which are always put on top for easy access.'),
    {18} ('This option causes the "Sand Impact" animation','to play when the weapon reaches its destination,','and it is on sand.','This option only works on unit types that act as','a weapon: the "Weapon rate of fire" has to be 0,','and the "Explode on target" option has to be','enabled.'),
    {19} ('This option forces the program to go through','the full number of script cycles for this unit,','even if the unit is outside of the user''s','screen area.','Normally, units outside of the screen area only','execute 1/10th of the script cycles, to save','CPU cycles.'),
    {20} ('The chance that a unit of this House will switch','sides when attacked by a Deviator.','','','The list only has rough values. You can use','[F3] or [F4] for more detailed editing.',''),
    {21} ('The MUSIC tracks are the MIDI tracks in the','game.','','','','',''),
    {22} ('The LETTER to put before the mentat voice','filenames to get the voices for this House.','','','','',''),
    {23} ('The PALACE SPECIAL ABILITY determines which','special weapon a Commander gets by building a','House Palace','','','',''),
    {24} ('GRAPHICS are all SHP graphics used by the game.','They are read from MOUSE.SHP, BTTN.ENG/GER/FRE,','SHAPES.SHP, UNITS2.SHP, UNITS1.SHP and','UNITS.SHP (in that order).','','Note that value 0 (normally the mouse arrow) is','sometimes used as "None" value.'),
    {25} ('UNIT GRAPHICS DISPLAY MODES determine how the  ','game draws this unit''s graphics. It determines  ','how many frames are shown for each direction.  ','','','',''),
    {26} ('ACTION INTERRUPT MODE. Determines how this','action is executed. It can either wait for the','previous action''s script to complete its current','cycle before starting this new one, abort the','current action immediately, or execute the new','action as subroutine without aborting the','previous action.'),
    {27} ('SIDEBAR MODE. Determines what mode the sidebar','will switch to to give this command.','','','','',''),
    {28} ('The RESPONSE SOUND is a sound clip from VOC.PAK','or one of the mentat PAK files.','These unit responses only work for infantry.','','','',''),
    {29} ('The PARENT FILE determines in which PAK archive','the game is going to look for this file.','','','','',''),
   //     [________________________________________________] = max length for each line
    {30} ('The FILE TYPE is an indicator of how the game',
          'handles this file.','','','','',''),
    {31} ('ANIMATION SCRIPT: This value is a reference to a','script that tells the game how to play this','structure''s animations. These scripts can''t be','edited, but you can see them in a detailed list.','','',''),
    {32} ('This option causes nearby units to automatically','attack this one. Units on which this option is','disabled will not be attacked by other units','automatically.','','',''),
    {33} ('This option is used to rank units and structures','in terms of importance, to make the AI select','more dangerous/vital units or structures first,','so it can attack or defend more effectively.','','',''),
    {34} ('This minimum and maximum set boundaries on where','the game is allowed to store units of this type','in its array of unit objects in memory.','','These boundaries separate the units in classes','like aircraft, ground units, weapons and special','stuff like the sandworm, Frigate and Saboteur.'),
    {35} ('These include things like the worm swallow','animation. The editor does not contain a list of','these yet.','','','',''),
    {36} ('This determines the index in ICON.MAP to use for','this structure''s graphics.','','The values in ICON.MAP determine which graphics','from ICON.ICN to use for each frame of the','structure.',''),
    {37} ('','','','','','',''),
    {38} ('','','','','','',''),
    {39} ('','','','','','',''),
    {40} ('','','','','','','')
    );


    // == END OF LISTS CONTROL ==


    // == TYPES CONTROL ==

    // DATA TYPE LIST - Editing description for each data type
    typedescr:array[0..32] of descr = (
    {00} ('Boolean (Yes/No)                    ',''),
    {01} ('Single byte (-128,127)              ',''),
    {02} ('Double byte (-32768,32767)          ',''),
    {03} ('Reference to 0-terminated string.   ','Give decimal offset in the EXE.     '),
    {04} ('Ownership. Press space to select or ','deselect a side.                    '),
    {05} ('Unit command. Select one from the   ','list.                               '),
    {06} ('Movement type.  Select one from the ','list.                               '),
    {07} ('Unit. Select one from the list.     ',''),
    {08} ('Foundation dimensions. Select one   ','from the list.                      '),
    {09} ('Decay factor. Indicates decay damage','dealt to structures of this house.  '),
    {10} ('Prerquisite structures. Press space ','to select or deselect a structure.  '),
    {11} ('Weapon Sounds. Select one from the  ','list.                               '),
    {12} ('Boolean (Yes/No) - bit 1            ',''),
    {13} ('Boolean (Yes/No) - bit 2            ',''),
    {14} ('Boolean (Yes/No) - bit 3            ',''),
    {15} ('Boolean (Yes/No) - bit 4            ',''),
    {16} ('Boolean (Yes/No) - bit 5            ',''),
    {17} ('Boolean (Yes/No) - bit 6            ',''),
    {18} ('Boolean (Yes/No) - bit 7            ',''),
    {19} ('Boolean (Yes/No) - bit 8            ',''),
    {20} ('Percentage. Select a value from the ','list or use [F4] for full editing.  '),
    {21} ('Music. Select a track from the list.',''),
    {22} ('Character. Type a character and     ','press [ENTER] to confirm.           '),
    {23} ('Palace Special Ability for this     ','House. Select one from the list.    '),
    {24} ('Graphics. Select one from the list. ','000 is sometimes used as "None" too.'),
    {25} ('Graphics display mode. Determines   ','how this unit''s frames are shown.   '),
    {26} ('Action interrupt mode. Determines   ','how this action is executed.        '),
    {27} ('Sidebar mode. Determines which      ','sidebar to use to give this command.'),
    {28} ('Sound clip. These are SB sound      ','files.                              '),
    {29} ('Parent PAK file. The .PAK archive   ','in which this file needs to be.     '),
    {30} ('File type. Determines how the game  ','handles this file.                  '),
    {31} ('Animation scripts can''t be edited,  ','but you can look at the actions.    '),
    {32} ('Structure graphics ID. Represents   ','an index in the ICON.MAP file.      ')
    );


    // Strings for specific data types

    booleans:array[0..1] of values = (
              (val: 0; txt: 'No'),
              (val: 1; txt: 'Yes')
              );

    foundations:array[0..6] of values = (
              (val: 0; txt: '1x1'),
              (val: 1; txt: '2x1'),
              (val: 2; txt: '1x2'),
              (val: 3; txt: '2x2'),
              (val: 4; txt: '2x3'),
              (val: 5; txt: '3x2'),
              (val: 6; txt: '3x3')
              );

    palaceSpecials:array[0..3] of values = (
              (val: 0; txt: 'None'),
              (val: 1; txt: 'Death Hand'),
              (val: 2; txt: 'Fremen'),
              (val: 3; txt: 'Saboteur')
              );
    displayModes:array[0..5] of values = (
              (val: 0; txt: 'Use single frame'),
              (val: 1; txt: 'Normal (unit)'),
              (val: 2; txt: 'Normal (weapon)'),
              (val: 3; txt: 'Normal frames * 3'),
              (val: 4; txt: 'Normal frames * 4'),
              (val: 5; txt: '''Thopter special')
              );
    interruptModes:array[0..2] of values = (
              (val: 0; txt: 'Finish action cycle'),
              (val: 1; txt: 'Interrupt action'),
              (val: 2; txt: 'Subroutine action')
              );
    sidebarModes:array[0..3] of values = (
              (val: 1; txt: 'Select target    '),
              (val: 2; txt: 'Place structure   (CRASHES)'),
              (val: 3; txt: 'Keep commands bar'),
              (val: 4; txt: 'Clear sidebar    ')
              );

    structureGraphics:array[0..25] of values = (
              (val: 1; txt: '01: Rock craters '),
              (val: 2; txt: '02: Sand craters '),
              (val: 3; txt: '03: Debris       '),
              (val: 4; txt: '04: Dead bodies  '),
              (val: 5; txt: '05: Sand tracks  '),
              (val: 6; txt: '06: Wall         '),
              (val: 7; txt: '07: Fog-of-war   '),
              (val: 8; txt: '08: Concrete slab'),
              (val: 9; txt: '09: landscape    '),
              (val:10; txt: '10: Spice blooms '),
              (val:11; txt: '11: House Palace '),
              (val:12; txt: '12: Light Factory'),
              (val:13; txt: '13: Heavy Factory'),
              (val:14; txt: '14: Hi-Tech      '),
              (val:15; txt: '15: IX           '),
              (val:16; txt: '16: WOR          '),
              (val:17; txt: '17: Constr. Yard '),
              (val:18; txt: '18: Barracks     '),
              (val:19; txt: '19: Windtrap     '),
              (val:20; txt: '20: Starport     '),
              (val:21; txt: '21: Refinery     '),
              (val:22; txt: '22: Repair       '),
              (val:23; txt: '23: Gun Turret   '),
              (val:24; txt: '24: Rocket Turret'),
              (val:25; txt: '25: Silo         '),
              (val:26; txt: '26: Radar Outpost')
              );

    sounds:array[0..35] of values = (
              (val:-1; txt: 'None                       '),
              (val: 0; txt: 'Not Applicable             '),
              (val:20; txt: 'Place down                 '),
              (val:22; txt: 'Twinkling                  '),
              (val:23; txt: 'Intro chord                '),
              (val:24; txt: 'Carryall dropoff           '),
              (val:30; txt: 'Infantry kill 1       (VOC)'),
              (val:35; txt: 'Infantry kill 2       (VOC)'),
              (val:33; txt: 'Infantry kill 3       (VOC)'),
              (val:34; txt: 'Infantry kill 4       (VOC)'),
              (val:31; txt: 'Infantry kill 5       (VOC)'),
              (val:36; txt: 'Infantry crush        (VOC)'),
              (val:38; txt: 'Click                 (VOC)'),
              (val:39; txt: 'Missile               (VOC)'),
              (val:40; txt: 'Hit sand              (VOC)'),
              (val:41; txt: 'Tank shot             (VOC)'),
              (val:42; txt: 'Rocket                (VOC)'),
              (val:43; txt: 'Sonic wave                 '),
              (val:44; txt: 'Structure crumble     (VOC)'),
              (val:46; txt: 'Death Hand target          '),
              (val:47; txt: '"Cannot Place" beep        '),
              (val:49; txt: 'Tank shot             (VOC)'),
              (val:55; txt: 'Tank shot             (VOC)'),
              (val:51; txt: 'Exploding unit        (VOC)'),
              (val:52; txt: 'Money increase             '),
              (val:53; txt: 'Money decrease             '),
              (val:54; txt: 'Weapon hit                 '),
              (val:56; txt: 'Tank shot             (VOC)'),
              (val:57; txt: 'Tank shot             (VOC)'),
              (val:58; txt: 'Single gun            (VOC)'),
              (val:59; txt: 'Machinegun            (VOC)'),
              (val:60; txt: '"Constr. Complete"    (VOC)'),
              (val:61; txt: 'Plingplong                 '),
              (val:62; txt: 'Radar static          (VOC)'),
              (val:63; txt: 'Worm attack           (VOC)'),
              (val:64; txt: 'Mini Rocket           (VOC)')
              );

    vocsounds:array[0..70] of values = (
              (val:-1; txt: 'None        '),
              (val: 0; txt: 'vscream1.voc'),
              (val: 1; txt: 'exsand.voc  '),
              (val: 2; txt: 'rocket.voc  '),
              (val: 3; txt: 'button.voc  '),
              (val: 4; txt: 'vscream5.voc'),
              (val: 5; txt: 'crumble.voc '),
              (val: 6; txt: 'exsmall.voc '),
              (val: 7; txt: 'exmed.voc   '),
              (val: 8; txt: 'exlarge.voc '),
              (val: 9; txt: 'excannon.voc'),
              (val:10; txt: 'gun.voc     '),
              (val:11; txt: 'gunmulti.voc'),
              (val:12; txt: 'exgas.voc   '),
              (val:13; txt: 'exdud.voc   '),
              (val:14; txt: 'vscream2.voc'),
              (val:15; txt: 'vscream3.voc'),
              (val:16; txt: 'vscream4.voc'),
              (val:17; txt: 'affirm.voc  '),
              (val:18; txt: 'report1.voc '),
              (val:19; txt: 'report2.voc '),
              (val:20; txt: 'report3.voc '),
              (val:21; txt: 'overout.voc '),
              (val:22; txt: 'moveout.voc '),
//            (val:23; txt: '[CORRUPTS GAME MEM]'),
              (val:24; txt: 'poppa.voc   '),
              (val:25; txt: 'sandbug.voc '),
              (val:26; txt: 'staticp.voc '),
              (val:27; txt: 'wormet3p.voc'),
              (val:28; txt: 'misltinp.voc'),
              (val:29; txt: 'squish2.voc '),
              (val:30; txt: '?enemy.voc  '),
              (val:31; txt: '?hark.voc   '),
              (val:32; txt: '?atre.voc   '),
              (val:33; txt: '?ordos.voc  '),
              (val:34; txt: '?fremen.voc '),
              (val:35; txt: '?sard.voc   '),
              (val:36; txt: '?merc.voc   (filler.voc)'),
              (val:37; txt: '?unit.voc   '),
              (val:38; txt: '?struct.voc '),
              (val:39; txt: '?one.voc    '),
              (val:40; txt: '?two.voc    '),
              (val:41; txt: '?three.voc  '),
              (val:42; txt: '?four.voc   '),
              (val:43; txt: '?five.voc   '),
              (val:44; txt: '?const.voc  '),
              (val:45; txt: '?radar.voc  '),
              (val:46; txt: '?off.voc    '),
              (val:47; txt: '?on.voc     '),
              (val:48; txt: '?frigate.voc'),
              (val:49; txt: '?arrive.voc '),
              (val:50; txt: '?warning.voc'),
              (val:51; txt: '?sabot.voc  '),
              (val:52; txt: '?missile.voc'),
              (val:53; txt: '?bloom.voc  '),
              (val:54; txt: '?destroy.voc'),
              (val:55; txt: '?deploy.voc '),
              (val:56; txt: '?apprch.voc '),
              (val:57; txt: '?located.voc'),
              (val:58; txt: '?north.voc  '),
              (val:59; txt: '?east.voc   '),
              (val:60; txt: '?south.voc  '),
              (val:61; txt: '?west.voc   '),
              (val:62; txt: '?win.voc    '),
              (val:63; txt: '?lose.voc   '),
              (val:64; txt: '?launch.voc '),
              (val:65; txt: '?attack.voc '),
              (val:66; txt: '?vehicle.voc'),
              (val:67; txt: '?repair.voc '),
              (val:68; txt: '?harvest.voc'),
              (val:69; txt: '?wormy.voc  '),
              (val:70; txt: '?capture.voc')
              );

    music:array[0..34] of values = (
              (val:-1; txt: 'None              '),
              (val: 1; txt: 'Ambient 1         '),
              (val: 2; txt: 'Ordos Defeat      '),
              (val: 3; txt: 'Harkonnen Defeat  '),
              (val: 4; txt: 'Atreides Defeat   '),
              (val: 5; txt: 'Ordos Win         '),
              (val: 6; txt: 'Harkonnen Win     '),
              (val: 7; txt: 'Atreides Win      '),
              (val: 8; txt: 'Ambient 2         '),
              (val: 9; txt: 'Ambient 3         '),
              (val:10; txt: 'Ambient 4         '),
              (val:11; txt: 'Ambient 5         '),
              (val:12; txt: 'Ambient 6         '),
              (val:13; txt: 'Ambient 7         '),
              (val:14; txt: 'Ambient 8         '),
              (val:15; txt: 'Ambient 9         '),
              (val:16; txt: 'Ambient 10        '),
              (val:17; txt: 'Attack 1          '),
              (val:18; txt: 'Attack 2          '),
              (val:19; txt: 'Attack 3          '),
              (val:20; txt: 'Attack 4          '),
              (val:21; txt: 'Attack 5          '),
              (val:22; txt: 'Attack 6          '),
              (val:24; txt: 'Harkonnen Mentat  '),
              (val:25; txt: 'Atreides Mentat   '),
              (val:26; txt: 'Ordos Mentat      '),
              (val:27; txt: 'Intro             '),
              (val:28; txt: 'Main Menu         '),
              (val:29; txt: 'Map Select        '),
              (val:30; txt: 'Harkonnen Ending  '),
              (val:31; txt: 'Atreides Ending   '),
              (val:32; txt: 'Ordos Ending      '),
              (val:33; txt: 'Ending Credits    '),
              (val:34; txt: 'Interlude         '),
              (val:36; txt: 'Westwood Logo     ')
              );

    percentages:array[0..4] of values = (
              (val: $00; txt: '00 %'),
              (val: $40; txt: '25 %'),
              (val: $80; txt: '50 %'),
              (val: $C0; txt: '75 %'),
              (val:$100; txt: '100%')
              );

    graphicsHi:array[0..354] of string[19] = (
                   //MOUSE.SHP
              {000} 'Mouse: arrow       ', // 000 - 000 is also used as "blank" sometimes.
              {001} 'Mouse: Scroll up   ', // 001
              {002} 'Mouse: Scroll left ', // 002
              {003} 'Mouse: Scroll down ', // 003
              {004} 'Mouse: Scroll right', // 004
              {005} 'Mouse: Target      ', // 005
              {006} 'Selection indicator', // 006
                   // BTTN.SHP
              {007} 'MENTAT button      ', // 000
              {008} 'MENTAT btn (pushed)', // 001
              {009} 'OPTIONS button     ', // 002
              {010} 'OPTIONS btn(pushed)', // 003
              {011} '"Credits" text     ', // 004
                   //SHAPES.SHP
              {012} 'Money Bar          ', // 000
              {013} 'Counter: empty     ', // 001
              {014} 'Counter: 0         ', // 002
              {015} 'Counter: 1         ', // 003
              {016} 'Counter: 2         ', // 004
              {017} 'Counter: 3         ', // 005
              {018} 'Counter: 4         ', // 006
              {019} 'Counter: 5         ', // 007
              {020} 'Counter: 6         ', // 008
              {021} 'Counter: 7         ', // 009
              {022} 'Counter: 8         ', // 010
              {023} 'Counter: 9         ', // 011
              {024} 'Foundation preview ', // 012
              {025} 'Option (unselected)', // 013
              {026} 'Option (selected)  ', // 014
              {027} 'Health indicators  ', // 015
              {028} 'Icon: Attack       ', // 016
              {039} 'Icon: Move         ', // 017
              {030} 'Icon: Death Hand   ', // 018
              {031} 'Red dot   2x2      ', // 019
              {032} 'Red dot   3x3      ', // 020
              {033} 'Blue dot  2x2      ', // 021
              {034} 'Blue dot  3x3      ', // 022
              {035} 'Green dot 2x2      ', // 023
              {036} 'Green dot 3x3      ', // 024
              {037} 'Sand dot 2x2       ', // 025
              {038} 'Sand dot 3x3       ', // 026
              {039} 'Concrete dot 2x2   ', // 027
              {040} 'Concrete dot 3x3   ', // 028
              {041} 'Spice dot 2x2      ', // 029
              {042} 'Spice dot 3x3      ', // 030
              {043} 'Dunes dot 2x2      ', // 031
              {044} 'Dunes dot 3x3      ', // 032
              {045} 'Rock dot 2x2       ', // 033
              {046} 'Rock dot 3x3       ', // 034
              {047} 'Dark concr dot 2x2 ', // 035
              {048} 'Dark concr dot 3x3 ', // 036
              {049} 'Black dot 2x2      ', // 037
              {040} 'Black dot 3x3      ', // 038
              {051} 'Dark blue dot 2x2  ', // 039
              {052} 'Dark blue dot 3x3  ', // 040
              {053} 'brown dot 2x2      ', // 041
              {054} 'brown dot 3x3      ', // 042
              {055} 'White dot 2x2      ', // 043
              {056} 'White dot 3x3      ', // 044
              {057} 'Dark brown dot 2x2 ', // 045
              {058} 'Dark brown dot 3x3 ', // 046
              {059} 'Arrow up           ', // 047
              {060} 'Arrow up (pushed)  ', // 048
              {061} 'Arrow down         ', // 049
              {062} 'Arrow down (pushed)', // 050
              {063} 'Foundation grid    ', // 051
              {064} 'Black square       ', // 052
              {065} 'Icon: Concrete Slab', // 053
              {066} 'Icon: Palace       ', // 054
              {067} 'Icon: Light Factory', // 055
              {068} 'Icon: Heavy Factory', // 056
              {069} 'Icon: Hi-Tech      ', // 057
              {070} 'Icon: House of IX  ', // 058
              {071} 'Icon: WOR          ', // 059
              {072} 'Icon: Constr. Yard ', // 060
              {073} 'Icon: Wind Trap    ', // 061
              {074} 'Icon: Barracks     ', // 062
              {075} 'Icon: Starport     ', // 063
              {076} 'Icon: Refinery     ', // 064
              {077} 'Icon: Repair       ', // 065
              {078} 'Icon: Wall         ', // 066
              {079} 'Icon: Gun Turret   ', // 067
              {080} 'Icon: Rocket turret', // 068
              {081} 'Icon: Silo         ', // 069
              {082} 'Icon: Radar Outpost', // 070
              {083} 'Icon: Large Concr. ', // 071
              {084} 'Icon: Siege Tank   ', // 072
              {085} 'Icon: Rocket Lnchr.', // 073
              {086} 'Icon: Quad         ', // 074
              {087} 'Icon: Devastator   ', // 075
              {088} 'Icon: Trooper      ', // 076
              {089} 'Icon: Carryall     ', // 077
              {090} 'Icon: Combat Tank  ', // 078
              {091} 'Icon: Sonic Tank   ', // 079
              {092} 'Icon: Trike        ', // 080
              {093} 'Icon: Inf. Squad   ', // 081
              {094} 'Icon: Fremen Squad ', // 082
              {095} 'Icon: Sardaukar    ', // 083
              {096} 'Icon: Saboteur     ', // 084
              {097} 'Icon: Ornithopter  ', // 085
              {098} 'Icon: Deviator     ', // 086
              {099} 'Icon: Raider Trike ', // 087
              {100} 'Icon: Harvester    ', // 088
              {101} 'Icon: MCV          ', // 089
              {102} 'Icon: Soldier      ', // 090
              {103} 'Icon: Trooper Squad', // 091
              {104} 'Icon: Fremen       ', // 092
              {105} 'Icon: Sandworm     ', // 093
              {106} 'Icon: Spice        ', // 094
              {107} 'Icon: Sand         ', // 095
              {108} 'Icon: Dunes        ', // 096
              {109} 'Icon: Rock         ', // 097
              {110} 'Icon: Mountain     ', // 098
                   //UNITS2.SHP
              {111} 'Small Tank body: N ', // 000
              {112} 'Small Tank body: NE', // 001
              {113} 'Small Tank body: E ', // 002
              {114} 'Small Tank body: SE', // 003
              {115} 'Small Tank body: S ', // 004
              {116} 'Small Tank turr: N ', // 005
              {117} 'Small Tank turr: NE', // 006
              {118} 'Small Tank turr: E ', // 007
              {119} 'Small Tank turr: SE', // 008
              {120} 'Small Tank turr: S ', // 009
              {121} 'Siege Tank body: N ', // 010
              {122} 'Siege Tank body: NE', // 011
              {123} 'Siege Tank body: E ', // 012
              {124} 'Siege Tank body: SE', // 013
              {125} 'Siege Tank body: S ', // 014
              {126} 'Siege Tank turr: N ', // 015
              {127} 'Siege Tank turr: NE', // 016
              {128} 'Siege Tank turr: E ', // 017
              {129} 'Siege Tank turr: SE', // 018
              {130} 'Siege Tank turr: S ', // 019
              {131} 'Devastator body: N ', // 020
              {132} 'Devastator body: NE', // 021
              {133} 'Devastator body: E ', // 022
              {134} 'Devastator body: SE', // 023
              {135} 'Devastator body: S ', // 024
              {136} 'Devastator turr: N ', // 025
              {137} 'Devastator turr: NE', // 026
              {138} 'Devastator turr: E ', // 027
              {139} 'Devastator turr: SE', // 028
              {140} 'Devastator turr: S ', // 029
              {141} 'Sonic tank turr: N ', // 030
              {142} 'Sonic tank turr: NE', // 031
              {143} 'Sonic tank turr: E ', // 032
              {144} 'Sonic tank turr: SE', // 033
              {145} 'Sonic tank turr: S ', // 034
              {146} 'R.Launcher turr: N ', // 035
              {147} 'R.Launcher turr: NE', // 036
              {148} 'R.Launcher turr: E ', // 037
              {149} 'R.Launcher turr: SE', // 038
              {150} 'R.Launcher turr: S ', // 039
                   //UNITS1.SHP
              {151} 'Lg explosion (#1)  ', // 000
              {152} 'Lg explosion (#2)  ', // 001
              {153} 'Cannon impact (#1) ', // 002
              {154} 'Cannon impact (#2) ', // 003
              {155} 'Cannon impact (#3) ', // 004
              {156} 'Sand impact (#1)   ', // 005
              {157} 'Sand impact (#2)   ', // 006
              {158} 'Sand impact (#3)   ', // 007
              {159} 'Sonic wave (#1)    ', // 008
              {160} 'Sonic wave (#2)    ', // 009
              {161} 'Sonic wave (#3)    ', // 010
              {162} 'Sm tank burn (#1)  ', // 011
              {163} 'Sm tank burn (#2)  ', // 012
              {164} 'Sm tank burn (#3)  ', // 013
              {165} 'Lg tank burn (#1)  ', // 014
              {166} 'Lg tank burn (#2)  ', // 015
              {167} 'Lg tank burn (#3)  ', // 016
              {168} 'Flames burn (#1)   ', // 017
              {169} 'Flames burn (#2)   ', // 018
              {170} 'Flames burn (#3)   ', // 019
              {171} 'Flames burn (#4)   ', // 020
              {172} 'Flames burn (#5)   ', // 021
              {173} 'Flames burn (#6)   ', // 022
              {174} 'Bullet (small)     ', // 023
              {175} 'Bullet (medium)    ', // 024
              {176} 'Bullet (large)     ', // 025
              {177} 'Wheel debris (#1)  ', // 026
              {178} 'Wheel debris (#2)  ', // 027
              {179} 'Wheel debris (#3)  ', // 028
              {180} 'Vehicle smoke (#1) ', // 029
              {181} 'Vehicle smoke (#2) ', // 030
              {182} 'Vehicle smoke (#3) ', // 031
              {183} 'Sm explosion (#1)  ', // 032
              {184} 'Sm explosion (#2)  ', // 033
              {185} 'Sm explosion (#3)  ', // 034
              {186} 'Sm explosion (#4)  ', // 035
              {187} 'Sm explosion (#5)  ', // 036
              {188} 'Lg explosion 1 (#1)', // 037
              {189} 'Lg explosion 1 (#2)', // 038
              {190} 'Lg explosion 1 (#3)', // 039
              {191} 'Lg explosion 1 (#4)', // 040
              {192} 'Lg explosion 1 (#5)', // 041
              {193} 'Lg explosion 2 (#1)', // 042
              {194} 'Lg explosion 2 (#2)', // 043
              {195} 'Lg explosion 2 (#3)', // 044
              {196} 'Lg explosion 2 (#4)', // 045
              {197} 'Lg explosion 2 (#5)', // 046
              {198} 'Lg explosion 3 (#1)', // 047
              {199} 'Lg explosion 3 (#2)', // 048
              {200} 'Lg explosion 3 (#3)', // 049
              {201} 'Lg explosion 3 (#4)', // 050
              {202} 'Lg explosion 3 (#5)', // 051
              {203} 'Lg explosion 4 (#1)', // 052
              {204} 'Lg explosion 4 (#2)', // 053
              {205} 'Lg explosion 4 (#3)', // 054
              {206} 'Lg explosion 4 (#4)', // 055
              {207} 'Lg explosion 4 (#5)', // 056
              {208} 'Deviator gas (#1)  ', // 057
              {209} 'Deviator gas (#2)  ', // 058
              {210} 'Deviator gas (#3)  ', // 059
              {211} 'Deviator gas (#4)  ', // 060
              {212} 'Deviator gas (#5)  ', // 061
              {213} 'Blank anim (#1)    ', // 062
              {214} 'Blank anim (#2)    ', // 063
              {215} 'Blank anim (#3)    ', // 064
              {216} 'Blank anim (#4)    ', // 065
              {217} 'Blank anim (#5)    ', // 066
              {218} 'Worm eat anim (#1) ', // 067
              {219} 'Worm eat anim (#2) ', // 068
              {220} 'Worm eat anim (#3) ', // 069
              {221} 'Worm eat anim (#4) ', // 070
              {222} 'Worm eat anim (#5) ', // 071
              {223} 'Harv anim N  (#1)  ', // 072
              {224} 'Harv anim N  (#2)  ', // 073
              {225} 'Harv anim N  (#3)  ', // 074
              {226} 'Harv anim NE (#1)  ', // 075
              {227} 'Harv anim NE (#2)  ', // 076
              {228} 'Harv anim NE (#3)  ', // 077
              {229} 'Harv anim E  (#1)  ', // 078
              {230} 'Harv anim E  (#2)  ', // 079
              {231} 'Harv anim E  (#3)  ', // 080
              {232} 'Harv anim SE (#1)  ', // 081
              {233} 'Harv anim SE (#2)  ', // 082
              {234} 'Harv anim SE (#3)  ', // 083
              {235} 'Harv anim S  (#1)  ', // 084
              {236} 'Harv anim S  (#2)  ', // 085
              {237} 'Harv anim S  (#3)  ', // 086
                   //UNITS.SHP
              {238} 'Quad: N            ', // 000
              {239} 'Quad: NE           ', // 001
              {240} 'Quad: E            ', // 002
              {241} 'Quad: SE           ', // 003
              {242} 'Quad: S            ', // 004
              {243} 'Trike: N           ', // 005
              {244} 'Trike: NE          ', // 006
              {245} 'Trike: E           ', // 007
              {246} 'Trike: SE          ', // 008
              {247} 'Trike: S           ', // 009
              {248} 'Harvester: N       ', // 010
              {249} 'Harvester: NE      ', // 011
              {250} 'Harvester: E       ', // 012
              {251} 'Harvester: SE      ', // 013
              {252} 'Harvester: S       ', // 014
              {253} 'MCV: N             ', // 015
              {254} 'MCV: NE            ', // 016
              {255} 'MCV: E             ', // 017
              {256} 'MCV: SE            ', // 018
              {257} 'MCV: S             ', // 019
              {258} 'Med rocket 1: N    ', // 020
              {259} 'Med rocket 1: NNE  ', // 021
              {260} 'Med rocket 1: NE   ', // 022
              {261} 'Med rocket 1: ENE  ', // 023
              {262} 'Med rocket 1: E    ', // 024
              {263} 'Med rocket 2: N    ', // 025
              {264} 'Med rocket 2: NNE  ', // 026
              {265} 'Med rocket 2: NE   ', // 027
              {266} 'Med rocket 2: ENE  ', // 028
              {267} 'Med rocket 2: E    ', // 029
              {268} 'Sm rocket 1: N     ', // 030
              {269} 'Sm rocket 1: NNE   ', // 031
              {270} 'Sm rocket 1: NE    ', // 032
              {271} 'Sm rocket 1: ENE   ', // 033
              {272} 'Sm rocket 1: E     ', // 034
              {273} 'Sm rocket 2: N     ', // 035
              {274} 'Sm rocket 2: NNE   ', // 036
              {275} 'Sm rocket 2: NE    ', // 037
              {276} 'Sm rocket 2: ENE   ', // 038
              {277} 'Sm rocket 2: E     ', // 039
              {278} 'Death Hand: N      ', // 040
              {279} 'Death Hand: NNE    ', // 041
              {280} 'Death Hand: NE     ', // 042
              {281} 'Death Hand: ENE    ', // 043
              {282} 'Death Hand: E      ', // 044
              {283} 'Empty Carryall: N  ', // 045
              {284} 'Empty Carryall: NE ', // 046
              {285} 'Empty Carryall: E  ', // 047
              {286} 'Full Carryall:  N  ', // 048
              {287} 'Full Carryall:  NE ', // 049
              {288} 'Full Carryall:  E  ', // 050
              {289} '''thopter: N  (#1)  ',// 051
              {290} '''thopter: N  (#2)  ',// 052
              {291} '''thopter: N  (#3)  ',// 053
              {292} '''thopter: NE (#1)  ',// 054
              {293} '''thopter: NE (#2)  ',// 055
              {294} '''thopter: NE (#3)  ',// 056
              {295} '''thopter: E  (#1)  ',// 057
              {296} '''thopter: E  (#2)  ',// 058
              {297} '''thopter: E  (#3)  ',// 059
              {298} 'Frigate: N         ', // 060
              {299} 'Frigate: NE        ', // 061
              {300} 'Frigate: E         ', // 062
              {301} 'Saboteur: N  (#1)  ', // 063
              {302} 'Saboteur: N  (#2)  ', // 064
              {303} 'Saboteur: N  (#3)  ', // 065
              {304} 'Saboteur: NE (#1)  ', // 066
              {305} 'Saboteur: NE (#2)  ', // 067
              {306} 'Saboteur: NE (#3)  ', // 068
              {307} 'Saboteur: E  (#1)  ', // 069
              {308} 'Saboteur: E  (#2)  ', // 070
              {309} 'Saboteur: E  (#3)  ', // 071
              {310} 'Saboteur: blow up? ', // 072
              {311} 'Soldier: N  (#1)   ', // 073
              {312} 'Soldier: N  (#2)   ', // 074
              {313} 'Soldier: N  (#3)   ', // 075
              {314} 'Soldier: NE (#1)   ', // 076
              {315} 'Soldier: NE (#2)   ', // 077
              {316} 'Soldier: NE (#3)   ', // 078
              {317} 'Soldier: E  (#1)   ', // 079
              {318} 'Soldier: E  (#2)   ', // 080
              {319} 'Soldier: E  (#3)   ', // 081
              {320} 'Trooper: N  (#1)   ', // 082
              {321} 'Trooper: N  (#2)   ', // 083
              {322} 'Trooper: N  (#3)   ', // 084
              {323} 'Trooper: NE (#1)   ', // 085
              {324} 'Trooper: NE (#2)   ', // 086
              {325} 'Trooper: NE (#3)   ', // 087
              {326} 'Trooper: E  (#1)   ', // 088
              {327} 'Trooper: E  (#2)   ', // 089
              {328} 'Trooper: E  (#3)   ', // 090
              {329} 'Inf Squad: N  (#1) ', // 091
              {330} 'Inf Squad: N  (#2) ', // 092
              {331} 'Inf Squad: N  (#3) ', // 093
              {332} 'Inf Squad: N  (#4) ', // 094
              {333} 'Inf Squad: NE (#1) ', // 095
              {334} 'Inf Squad: NE (#2) ', // 096
              {335} 'Inf Squad: NE (#3) ', // 097
              {336} 'Inf Squad: NE (#4) ', // 098
              {337} 'Inf Squad: E  (#1) ', // 099
              {338} 'Inf Squad: E  (#2) ', // 100
              {339} 'Inf Squad: E  (#3) ', // 101
              {340} 'Inf Squad: E  (#4) ', // 102
              {341} 'Troopers: N  (#1)  ', // 103
              {342} 'Troopers: N  (#2)  ', // 104
              {343} 'Troopers: N  (#3)  ', // 105
              {344} 'Troopers: N  (#4)  ', // 106
              {345} 'Troopers: NE (#1)  ', // 107
              {346} 'Troopers: NE (#2)  ', // 108
              {347} 'Troopers: NE (#3)  ', // 109
              {348} 'Troopers: NE (#4)  ', // 110
              {349} 'Troopers: E  (#1)  ', // 111
              {350} 'Troopers: E  (#2)  ', // 112
              {351} 'Troopers: E  (#3)  ', // 113
              {352} 'Troopers: E  (#4)  ', // 114
              {353} 'Landed ornithopter ', // 115
              {354} 'Transparent pixel  '  // 116
              );

    graphicsLo:array[0..353] of string[19] = (
                   //MOUSE.SHP
              {000} 'Mouse: arrow       ', // 000 - 000 is also used as "blank" sometimes.
              {001} 'Mouse: Scroll up   ', // 001
              {002} 'Mouse: Scroll left ', // 002
              {003} 'Mouse: Scroll down ', // 003
              {004} 'Mouse: Scroll right', // 004
              {005} 'Mouse: Target      ', // 005
              {006} 'Selection indicator', // 006
                   //SHAPES.SHP
              {007} 'Money Bar          ', // 000
              {008} 'Counter: empty     ', // 001
              {009} 'Counter: 0         ', // 002
              {010} 'Counter: 1         ', // 003
              {011} 'Counter: 2         ', // 004
              {012} 'Counter: 3         ', // 005
              {013} 'Counter: 4         ', // 006
              {014} 'Counter: 5         ', // 007
              {015} 'Counter: 6         ', // 008
              {016} 'Counter: 7         ', // 009
              {017} 'Counter: 8         ', // 010
              {018} 'Counter: 9         ', // 011
              {019} 'Foundation preview ', // 012
              {020} 'Option (unselected)', // 013
              {021} 'Option (selected)  ', // 014
              {022} 'Health indicators  ', // 015
              {023} 'Icon: Attack       ', // 016
              {024} 'Icon: Move         ', // 017
              {025} 'Icon: Death Hand   ', // 018
              {026} 'Red dot   2x2      ', // 019
              {027} 'Red dot   3x3      ', // 020
              {028} 'Blue dot  2x2      ', // 021
              {029} 'Blue dot  3x3      ', // 022
              {030} 'Green dot 2x2      ', // 023
              {031} 'Green dot 3x3      ', // 024
              {032} 'Sand dot 2x2       ', // 025
              {033} 'Sand dot 3x3       ', // 026
              {034} 'Concrete dot 2x2   ', // 027
              {035} 'Concrete dot 3x3   ', // 028
              {036} 'Spice dot 2x2      ', // 029
              {037} 'Spice dot 3x3      ', // 030
              {038} 'Dunes dot 2x2      ', // 031
              {039} 'Dunes dot 3x3      ', // 032
              {040} 'Rock dot 2x2       ', // 033
              {041} 'Rock dot 3x3       ', // 034
              {042} 'Dark concr dot 2x2 ', // 035
              {043} 'Dark concr dot 3x3 ', // 036
              {044} 'Black dot 2x2      ', // 037
              {045} 'Black dot 3x3      ', // 038
              {046} 'Dark blue dot 2x2  ', // 039
              {047} 'Dark blue dot 3x3  ', // 040
              {048} 'brown dot 2x2      ', // 041
              {049} 'brown dot 3x3      ', // 042
              {050} 'White dot 2x2      ', // 043
              {051} 'White dot 3x3      ', // 044
              {052} 'Dark brown dot 2x2 ', // 045
              {053} 'Dark brown dot 3x3 ', // 046
              {054} 'Arrow up           ', // 047
              {055} 'Arrow up (pushed)  ', // 048
              {056} 'Arrow down         ', // 049
              {057} 'Arrow down (pushed)', // 050
              {058} 'Foundation grid    ', // 051
              {059} 'Black square       ', // 052
              {060} 'Icon: Concrete Slab', // 053
              {061} 'Icon: Palace       ', // 054
              {062} 'Icon: Light Factory', // 055
              {063} 'Icon: Heavy Factory', // 056
              {064} 'Icon: Hi-Tech      ', // 057
              {065} 'Icon: House of IX  ', // 058
              {066} 'Icon: WOR          ', // 059
              {067} 'Icon: Constr. Yard ', // 060
              {068} 'Icon: Wind Trap    ', // 061
              {069} 'Icon: Barracks     ', // 062
              {070} 'Icon: Starport     ', // 063
              {071} 'Icon: Refinery     ', // 064
              {072} 'Icon: Repair       ', // 065
              {073} 'Icon: Wall         ', // 066
              {074} 'Icon: Gun Turret   ', // 067
              {075} 'Icon: Rocket turret', // 068
              {076} 'Icon: Silo         ', // 069
              {077} 'Icon: Radar Outpost', // 070
              {078} 'Icon: Large Concr. ', // 071
              {079} 'Icon: Siege Tank   ', // 072
              {080} 'Icon: Rocket Lnchr.', // 073
              {081} 'Icon: Quad         ', // 074
              {082} 'Icon: Devastator   ', // 075
              {083} 'Icon: Trooper      ', // 076
              {084} 'Icon: Carryall     ', // 077
              {085} 'Icon: Combat Tank  ', // 078
              {086} 'Icon: Sonic Tank   ', // 079
              {087} 'Icon: Trike        ', // 080
              {088} 'Icon: Inf. Squad   ', // 081
              {089} 'Icon: Fremen Squad ', // 082
              {090} 'Icon: Sardaukar    ', // 083
              {091} 'Icon: Saboteur     ', // 084
              {092} 'Icon: Ornithopter  ', // 085
              {093} 'Icon: Deviator     ', // 086
              {094} 'Icon: Raider Trike ', // 087
              {095} 'Icon: Harvester    ', // 088
              {096} 'Icon: MCV          ', // 089
              {097} 'Icon: Soldier      ', // 090
              {098} 'Icon: Trooper Squad', // 091
              {099} 'Icon: Fremen       ', // 092
              {100} 'Icon: Sandworm     ', // 093
              {101} 'MENTAT button      ', // 094
              {102} 'MENTAT btn (pushed)', // 095
              {103} 'OPTIONS button     ', // 096
              {104} 'OPTIONS btn(pushed)', // 097
              {105} 'Icon: Spice        ', // 098
              {106} 'Icon: Sand         ', // 099
              {107} 'Icon: Dunes        ', // 100
              {108} 'Icon: Rock         ', // 101
              {109} 'Icon: Mountain     ', // 102
                   //UNITS2.SHP
              {110} 'Small Tank body: N ', // 000
              {111} 'Small Tank body: NE', // 001
              {112} 'Small Tank body: E ', // 002
              {113} 'Small Tank body: SE', // 003
              {114} 'Small Tank body: S ', // 004
              {115} 'Small Tank turr: N ', // 005
              {116} 'Small Tank turr: NE', // 006
              {117} 'Small Tank turr: E ', // 007
              {118} 'Small Tank turr: SE', // 008
              {119} 'Small Tank turr: S ', // 009
              {120} 'Siege Tank body: N ', // 010
              {121} 'Siege Tank body: NE', // 011
              {122} 'Siege Tank body: E ', // 012
              {123} 'Siege Tank body: SE', // 013
              {124} 'Siege Tank body: S ', // 014
              {125} 'Siege Tank turr: N ', // 015
              {126} 'Siege Tank turr: NE', // 016
              {127} 'Siege Tank turr: E ', // 017
              {128} 'Siege Tank turr: SE', // 018
              {129} 'Siege Tank turr: S ', // 019
              {130} 'Devastator body: N ', // 020
              {131} 'Devastator body: NE', // 021
              {132} 'Devastator body: E ', // 022
              {133} 'Devastator body: SE', // 023
              {134} 'Devastator body: S ', // 024
              {135} 'Devastator turr: N ', // 025
              {136} 'Devastator turr: NE', // 026
              {137} 'Devastator turr: E ', // 027
              {138} 'Devastator turr: SE', // 028
              {139} 'Devastator turr: S ', // 029
              {140} 'Sonic tank turr: N ', // 030
              {141} 'Sonic tank turr: NE', // 031
              {142} 'Sonic tank turr: E ', // 032
              {143} 'Sonic tank turr: SE', // 033
              {144} 'Sonic tank turr: S ', // 034
              {145} 'R.Launcher turr: N ', // 035
              {146} 'R.Launcher turr: NE', // 036
              {147} 'R.Launcher turr: E ', // 037
              {148} 'R.Launcher turr: SE', // 038
              {149} 'R.Launcher turr: S ', // 039
                   //UNITS1.SHP
              {150} 'Lg explosion (#1)  ', // 000
              {151} 'Lg explosion (#2)  ', // 001
              {152} 'Cannon impact (#1) ', // 002
              {153} 'Cannon impact (#2) ', // 003
              {154} 'Cannon impact (#3) ', // 004
              {155} 'Sand impact (#1)   ', // 005
              {156} 'Sand impact (#2)   ', // 006
              {157} 'Sand impact (#3)   ', // 007
              {158} 'Sonic wave (#1)    ', // 008
              {159} 'Sonic wave (#2)    ', // 009
              {160} 'Sonic wave (#3)    ', // 010
              {161} 'Sm tank burn (#1)  ', // 011
              {162} 'Sm tank burn (#2)  ', // 012
              {163} 'Sm tank burn (#3)  ', // 013
              {164} 'Lg tank burn (#1)  ', // 014
              {165} 'Lg tank burn (#2)  ', // 015
              {166} 'Lg tank burn (#3)  ', // 016
              {167} 'Flames burn (#1)   ', // 017
              {168} 'Flames burn (#2)   ', // 018
              {169} 'Flames burn (#3)   ', // 019
              {170} 'Flames burn (#4)   ', // 020
              {171} 'Flames burn (#5)   ', // 021
              {172} 'Flames burn (#6)   ', // 022
              {173} 'Bullet (small)     ', // 023
              {174} 'Bullet (medium)    ', // 024
              {175} 'Bullet (large)     ', // 025
              {176} 'Wheel debris (#1)  ', // 026
              {177} 'Wheel debris (#2)  ', // 027
              {178} 'Wheel debris (#3)  ', // 028
              {179} 'Vehicle smoke (#1) ', // 029
              {180} 'Vehicle smoke (#2) ', // 030
              {181} 'Vehicle smoke (#3) ', // 031
              {182} 'Sm explosion (#1)  ', // 032
              {183} 'Sm explosion (#2)  ', // 033
              {184} 'Sm explosion (#3)  ', // 034
              {185} 'Sm explosion (#4)  ', // 035
              {186} 'Sm explosion (#5)  ', // 036
              {187} 'Lg explosion 1 (#1)', // 037
              {188} 'Lg explosion 1 (#2)', // 038
              {189} 'Lg explosion 1 (#3)', // 039
              {190} 'Lg explosion 1 (#4)', // 040
              {191} 'Lg explosion 1 (#5)', // 041
              {192} 'Lg explosion 2 (#1)', // 042
              {193} 'Lg explosion 2 (#2)', // 043
              {194} 'Lg explosion 2 (#3)', // 044
              {195} 'Lg explosion 2 (#4)', // 045
              {196} 'Lg explosion 2 (#5)', // 046
              {197} 'Lg explosion 3 (#1)', // 047
              {198} 'Lg explosion 3 (#2)', // 048
              {199} 'Lg explosion 3 (#3)', // 049
              {200} 'Lg explosion 3 (#4)', // 050
              {201} 'Lg explosion 3 (#5)', // 051
              {202} 'Lg explosion 4 (#1)', // 052
              {203} 'Lg explosion 4 (#2)', // 053
              {204} 'Lg explosion 4 (#3)', // 054
              {205} 'Lg explosion 4 (#4)', // 055
              {206} 'Lg explosion 4 (#5)', // 056
              {207} 'Deviator gas (#1)  ', // 057
              {208} 'Deviator gas (#2)  ', // 058
              {209} 'Deviator gas (#3)  ', // 059
              {210} 'Deviator gas (#4)  ', // 060
              {211} 'Deviator gas (#5)  ', // 061
              {212} 'Blank anim (#1)    ', // 062
              {213} 'Blank anim (#2)    ', // 063
              {214} 'Blank anim (#3)    ', // 064
              {215} 'Blank anim (#4)    ', // 065
              {216} 'Blank anim (#5)    ', // 066
              {217} 'Worm eat anim (#1) ', // 067
              {218} 'Worm eat anim (#2) ', // 068
              {219} 'Worm eat anim (#3) ', // 069
              {220} 'Worm eat anim (#4) ', // 070
              {221} 'Worm eat anim (#5) ', // 071
              {222} 'Harv anim N  (#1)  ', // 072
              {223} 'Harv anim N  (#2)  ', // 073
              {224} 'Harv anim N  (#3)  ', // 074
              {225} 'Harv anim NE (#1)  ', // 075
              {226} 'Harv anim NE (#2)  ', // 076
              {227} 'Harv anim NE (#3)  ', // 077
              {228} 'Harv anim E  (#1)  ', // 078
              {229} 'Harv anim E  (#2)  ', // 079
              {230} 'Harv anim E  (#3)  ', // 080
              {231} 'Harv anim SE (#1)  ', // 081
              {232} 'Harv anim SE (#2)  ', // 082
              {233} 'Harv anim SE (#3)  ', // 083
              {234} 'Harv anim S  (#1)  ', // 084
              {235} 'Harv anim S  (#2)  ', // 085
              {236} 'Harv anim S  (#3)  ', // 086
                   //UNITS.SHP
              {237} 'Quad: N            ', // 000
              {238} 'Quad: NE           ', // 001
              {239} 'Quad: E            ', // 002
              {240} 'Quad: SE           ', // 003
              {241} 'Quad: S            ', // 004
              {242} 'Trike: N           ', // 005
              {243} 'Trike: NE          ', // 006
              {244} 'Trike: E           ', // 007
              {245} 'Trike: SE          ', // 008
              {246} 'Trike: S           ', // 009
              {247} 'Harvester: N       ', // 010
              {248} 'Harvester: NE      ', // 011
              {249} 'Harvester: E       ', // 012
              {250} 'Harvester: SE      ', // 013
              {251} 'Harvester: S       ', // 014
              {252} 'MCV: N             ', // 015
              {253} 'MCV: NE            ', // 016
              {254} 'MCV: E             ', // 017
              {255} 'MCV: SE            ', // 018
              {256} 'MCV: S             ', // 019
              {257} 'Med rocket 1: N    ', // 020
              {258} 'Med rocket 1: NNE  ', // 021
              {259} 'Med rocket 1: NE   ', // 022
              {260} 'Med rocket 1: ENE  ', // 023
              {261} 'Med rocket 1: E    ', // 024
              {262} 'Med rocket 2: N    ', // 025
              {263} 'Med rocket 2: NNE  ', // 026
              {264} 'Med rocket 2: NE   ', // 027
              {265} 'Med rocket 2: ENE  ', // 028
              {266} 'Med rocket 2: E    ', // 029
              {267} 'Sm rocket 1: N     ', // 030
              {268} 'Sm rocket 1: NNE   ', // 031
              {269} 'Sm rocket 1: NE    ', // 032
              {270} 'Sm rocket 1: ENE   ', // 033
              {271} 'Sm rocket 1: E     ', // 034
              {272} 'Sm rocket 2: N     ', // 035
              {273} 'Sm rocket 2: NNE   ', // 036
              {274} 'Sm rocket 2: NE    ', // 037
              {275} 'Sm rocket 2: ENE   ', // 038
              {276} 'Sm rocket 2: E     ', // 039
              {277} 'Death Hand: N      ', // 040
              {278} 'Death Hand: NNE    ', // 041
              {279} 'Death Hand: NE     ', // 042
              {280} 'Death Hand: ENE    ', // 043
              {281} 'Death Hand: E      ', // 044
              {282} 'Empty Carryall: N  ', // 045
              {283} 'Empty Carryall: NE ', // 046
              {284} 'Empty Carryall: E  ', // 047
              {285} 'Full Carryall:  N  ', // 048
              {286} 'Full Carryall:  NE ', // 049
              {287} 'Full Carryall:  E  ', // 050
              {288} '''thopter: N  (#1)  ',// 051
              {289} '''thopter: N  (#2)  ',// 052
              {290} '''thopter: N  (#3)  ',// 053
              {291} '''thopter: NE (#1)  ',// 054
              {292} '''thopter: NE (#2)  ',// 055
              {293} '''thopter: NE (#3)  ',// 056
              {294} '''thopter: E  (#1)  ',// 057
              {295} '''thopter: E  (#2)  ',// 058
              {296} '''thopter: E  (#3)  ',// 059
              {297} 'Frigate: N         ', // 060
              {298} 'Frigate: NE        ', // 061
              {299} 'Frigate: E         ', // 062
              {300} 'Saboteur: N  (#1)  ', // 063
              {301} 'Saboteur: N  (#2)  ', // 064
              {302} 'Saboteur: N  (#3)  ', // 065
              {303} 'Saboteur: NE (#1)  ', // 066
              {304} 'Saboteur: NE (#2)  ', // 067
              {305} 'Saboteur: NE (#3)  ', // 068
              {306} 'Saboteur: E  (#1)  ', // 069
              {307} 'Saboteur: E  (#2)  ', // 070
              {308} 'Saboteur: E  (#3)  ', // 071
              {309} 'Saboteur: blow up? ', // 072
              {310} 'Soldier: N  (#1)   ', // 073
              {311} 'Soldier: N  (#2)   ', // 074
              {312} 'Soldier: N  (#3)   ', // 075
              {313} 'Soldier: NE (#1)   ', // 076
              {314} 'Soldier: NE (#2)   ', // 077
              {315} 'Soldier: NE (#3)   ', // 078
              {316} 'Soldier: E  (#1)   ', // 079
              {317} 'Soldier: E  (#2)   ', // 080
              {318} 'Soldier: E  (#3)   ', // 081
              {319} 'Trooper: N  (#1)   ', // 082
              {320} 'Trooper: N  (#2)   ', // 083
              {321} 'Trooper: N  (#3)   ', // 084
              {322} 'Trooper: NE (#1)   ', // 085
              {323} 'Trooper: NE (#2)   ', // 086
              {324} 'Trooper: NE (#3)   ', // 087
              {325} 'Trooper: E  (#1)   ', // 088
              {326} 'Trooper: E  (#2)   ', // 089
              {327} 'Trooper: E  (#3)   ', // 090
              {328} 'Inf Squad: N  (#1) ', // 091
              {329} 'Inf Squad: N  (#2) ', // 092
              {330} 'Inf Squad: N  (#3) ', // 093
              {331} 'Inf Squad: N  (#4) ', // 094
              {332} 'Inf Squad: NE (#1) ', // 095
              {333} 'Inf Squad: NE (#2) ', // 096
              {334} 'Inf Squad: NE (#3) ', // 097
              {335} 'Inf Squad: NE (#4) ', // 098
              {336} 'Inf Squad: E  (#1) ', // 099
              {337} 'Inf Squad: E  (#2) ', // 100
              {338} 'Inf Squad: E  (#3) ', // 101
              {339} 'Inf Squad: E  (#4) ', // 102
              {340} 'Troopers: N  (#1)  ', // 103
              {341} 'Troopers: N  (#2)  ', // 104
              {342} 'Troopers: N  (#3)  ', // 105
              {343} 'Troopers: N  (#4)  ', // 106
              {344} 'Troopers: NE (#1)  ', // 107
              {345} 'Troopers: NE (#2)  ', // 108
              {346} 'Troopers: NE (#3)  ', // 109
              {347} 'Troopers: NE (#4)  ', // 110
              {348} 'Troopers: E  (#1)  ', // 111
              {349} 'Troopers: E  (#2)  ', // 112
              {350} 'Troopers: E  (#3)  ', // 113
              {351} 'Troopers: E  (#4)  ', // 114
              {352} 'Landed ornithopter ', // 115
              {353} 'Transparent pixel  '  // 116
              );

    fileTypes:array[0..2] of values = (
              (val:  0; txt: 'PAK file'),
              (val:  6; txt: 'XMS/EMS loaded PAK file'),
              (val: 16; txt: 'Data file')
              );

    decayFactors:array[0..10] of values = (
              (val: -1; txt: 'No decay'),
              (val:  0; txt: '0 (damage=1)'),
              (val:  1; txt: '1 (damage=2)'),
              (val:  2; txt: '2 (damage=3)'),
              (val:  3; txt: '3 (damage=4)'),
              (val:  4; txt: '4 (damage=5)'),
              (val:  5; txt: '5 (damage=6)'),
              (val:  6; txt: '6 (damage=7)'),
              (val:  7; txt: '7 (damage=8)'),
              (val:  8; txt: '8 (damage=9)'),
              (val:  9; txt: '9 (damage=10)')
              );


  // default EMPTY command used when removing script command, so the editor
  // sees the full available editing space.
  // User will not be able to add empty command manually: when an ending command
  // is inserted, all following lines will have to be automatically cleared with
  // this value.
    defaultEmptyAnimScriptLine:scriptLine = (command: $F; argument:$314);

    structAnim:array[0..9] of scriptvalues = (
      (val: $0; isEnd: true;  hasArg: false; shorttxt: 'RM'; longtxt: 'Remove from map (#1)    '),
      (val: $1; isEnd: true;  hasArg: false; shorttxt: 'ST'; longtxt: 'Stop animation          '),
      (val: $2; isEnd: false; hasArg: false; shorttxt: '??'; longtxt: 'Unknown                 '),
      (val: $3; isEnd: false; hasArg: true;  shorttxt: 'WT'; longtxt: 'Wait for amount of time '),
      (val: $4; isEnd: true;  hasArg: false; shorttxt: 'LP'; longtxt: 'Loop (Jump to step 0)   '),
      (val: $5; isEnd: false; hasArg: true;  shorttxt: 'SN'; longtxt: 'Play Sound with ID      '),
      (val: $6; isEnd: false; hasArg: true;  shorttxt: 'FR'; longtxt: 'Change graphics frame to'),
      (val: $7; isEnd: true;  hasArg: true;  shorttxt: 'JM'; longtxt: 'Jump back # script steps'),
      (val: $8; isEnd: false; hasArg: true;  shorttxt: 'ID'; longtxt: 'Change graphics ID to   '),
      (val: $9; isEnd: true;  hasArg: false; shorttxt: 'RM'; longtxt: 'Remove from map (dup)   ')
      );

      // "special animation" in unit opts is an index in a list of refs to animations.
      // These are the commands used in these animations.
      // Not sure if I'll ever be able to use these. Unlike the buildings, there are no direct
      // references to them. Units use an animation ID instead. This probably means there's
      // a nice ordered list of them somewhere though, to link them to those IDs.
    unitAnim:array[0..14] of scriptvalues = (
      (val: $0; isEnd: true;  hasArg: false; shorttxt: 'ST'; longtxt: 'Stop animation          '),
      (val: $1; isEnd: false; hasArg: true;  shorttxt: 'FF'; longtxt: '[False] Change frame to '),
      (val: $2; isEnd: false; hasArg: true;  shorttxt: 'WT'; longtxt: 'Wait for amount of time '),
      (val: $3; isEnd: false; hasArg: true;  shorttxt: 'WR'; longtxt: 'Wait for random time  < '),
      (val: $4; isEnd: false; hasArg: true;  shorttxt: 'TF'; longtxt: '[True]  Change frame to '),
      (val: $5; isEnd: true;  hasArg: false; shorttxt: 'LP'; longtxt: 'Loop (Jump to step 0)   '),
      (val: $6; isEnd: false; hasArg: true;  shorttxt: 'PS'; longtxt: 'modify position cell    '),
      (val: $7; isEnd: false; hasArg: true;  shorttxt: 'PS'; longtxt: 'modify pos. cell (dup)  '),
      (val: $8; isEnd: false; hasArg: true;  shorttxt: 'B?'; longtxt: 'Bloom check?            '),
      (val: $9; isEnd: false; hasArg: true;  shorttxt: 'SN'; longtxt: 'Play Sound with ID      '),
      (val: $A; isEnd: false; hasArg: true;  shorttxt: 'RV'; longtxt: 'Revealed check?         '),
      (val: $B; isEnd: false; hasArg: true;  shorttxt: 'ST'; longtxt: 'Structure anim?         '),
      (val: $C; isEnd: true;  hasArg: false; shorttxt: 'ST'; longtxt: 'Stop animation (dup1)   '),
      (val: $D; isEnd: false; hasArg: true;  shorttxt: 'BK'; longtxt: 'Spice Bloom kills unit  '),
      (val: $E; isEnd: true;  hasArg: false; shorttxt: 'ST'; longtxt: 'Stop animation (dup2)   ')
      );

    // == END OF TYPES CONTROL ==

// =========================================
//                 MISCELLANEOUS
// =========================================

// To convert value to string on the fly without needing a variable to store it in.
function toString(b:boolean):String;
begin
  str(byte(b),toString);
end;

function toString(b:byte):String;
begin
  str(b,toString);
end;

function toString(i:Integer):String;
begin
  str(i,toString);
end;

// Press Key To Continue procedure with buffer clear.
procedure cntin(Msg:String);
begin
   if (length(Msg)>0) then
    begin
     writeln();
     write(Msg);
    end;
   repeat until keypressed;
    ReadKey();
   while keypressed do ReadKey(); {Clears the keyboard buffer}
   if (length(Msg)>0) then writeln();
end; {cntin}

procedure cntin();
begin
  cntin('');
end; {cntin}

procedure cntin(showMsg:boolean);
begin
  if showMsg then cntin('Press any key to continue. . . ')
  else            cntin('');
end; {cntin}

// Sets cursor to end of page to 'hide' it.
procedure resetCursor();
begin
  gotoxy(80,25);
end;

function capitalize(str:string):String;
begin
   if (byte(str[1])>=97) and (byte(str[1])<=122) then str[1]:=char(byte(str[1])-32);
   capitalize:=str;
end;

function isNumeric(s:string):boolean;
Var
  val,i: integer;
begin
  isNumeric:=true;
  for i:=1 to length(s) do
   begin
    val:=byte(s[i])-48;
    if (val<0) or (val>9) then isNumeric:=false;
   end;
end;

function GetWord(startstr:string;wordnumber:integer;delim:string):String;
begin
  startstr:=startstr+delim;
  while wordnumber > 1 do
    begin
     startstr:=copy(startstr,pos(delim,startstr)+length(delim),(length(startstr)-pos(delim,startstr)));
     wordnumber:=wordnumber-1;
    end;
  if pos(delim,startstr) > 0 then GetWord:=copy(startstr,1,pos(delim,startstr)-1)
  else GetWord:=startstr;
end;

// For abbreviating prerequisites & options to 4 characters
function smartAbbrev(toAbbrev:string):string;
var
  firstword:string;
  secondword:string;
begin
  smartAbbrev:='';

  if (pos(' ',toAbbrev) = 0) and (pos('-',toAbbrev) = 0) then
    begin
      firstword:=toAbbrev;
      secondword:='';
    end;
  if (pos(' ',toAbbrev) = 0)
     OR (   (pos(' ',toAbbrev) <> 0) and (pos('-',toAbbrev) <> 0)
             and (pos(' ',toAbbrev) > pos('-',toAbbrev))
        ) then
    begin
      firstword:=GetWord(toAbbrev,1,'-');
      secondword:=GetWord(toAbbrev,2,'-');
    end;

  if (pos('-',toAbbrev) = 0)
     OR (   (pos(' ',toAbbrev) <> 0) and (pos('-',toAbbrev) <> 0)
             and (pos(' ',toAbbrev) < pos('-',toAbbrev))
        ) then
    begin
      firstword:=GetWord(toAbbrev,1,' ');
      secondword:=GetWord(toAbbrev,2,' ');
    end;

    firstword:=capitalize(firstword);
    secondword:=capitalize(secondword);

  if SecondWord<>'' then
    begin
      if length(secondword)=1 then
        smartAbbrev:=copy(firstword,1,3) + secondword
      else if length(firstword)>2 then
        smartAbbrev:=copy(firstword,1,2) + copy(secondword,1,2)
      else
        smartAbbrev:=copy(concat(firstword,copy(secondword,1,3)),1,4);
    end
  else
    begin
      if isNumeric(copy(firstword,length(firstword)-2, 3)) then
        smartAbbrev:=copy(firstword,1,1) + Copy(firstword, length(firstword)-2, 3)
      else if isNumeric(Copy(firstword, length(firstword)-1, 2)) then
        smartAbbrev:=copy(firstword,1,2) + Copy(firstword, length(firstword)-1, 2)
      else if isNumeric(firstword[length(firstword)]) then
        smartAbbrev:=copy(firstword,1,3) + Copy(firstword, length(firstword), 1)
      else smartAbbrev:=copy(firstword,1,4);
    end;
end;

// General data display functions. Keep in mind that "fourbyte" is little-endian.

function fourbyte2int(data:fourbyte;nrofbytes:byte):integer;
var i:integer;
begin
  fourbyte2int:=0;
  for i:=0 to 3 do
    fourbyte2int:=fourbyte2int*$100+data[i];

  // adjust for zero-value of 2-byte and 1-byte values
  if nrofbytes < 3 then if (fourbyte2int>=(floor(power(256,nrofbytes)) div 2))
   then fourbyte2int:=(fourbyte2int-floor(power(256,nrofbytes)));
end;

function fourbyte2int(data:fourbyte):integer;
begin
  fourbyte2int:=fourbyte2int(data,4);
end;

// Little-endian: Lowest value in latest byte
function int2fourbyte(data:integer):fourbyte;
var data2,i:integer;
begin
  data2:=data;
  if data >= 0 then
   for i:=3 downto 0 do
    begin
      int2fourbyte[i]:=data2 mod $100;
      data2:=data2 div $100;
    end
  else
   begin
     data2:=maxint+data+1; // remove highest bit
     for i:=3 downto 1 do
      begin
        int2fourbyte[i]:=data2 mod $100;
        data2:=data2 div $100;
      end;
     int2fourbyte[0]:=$80+(data2 mod $100); // restore highest bit
   end;
end;

function hexchar2byte(hex:char):byte;
begin
  hexchar2byte:=0;
  if (byte(hex)>=65) and (byte(hex)<=70) then hexchar2byte:=byte(hex)-55
  else if (byte(hex)>=48) and (byte(hex)<=57) then hexchar2byte:=byte(hex)-48
end;

function hexstr2byte(hex:string[2]):byte;
var multiplier:integer;
begin
  hexstr2byte:=0;
  multiplier:=16;
  if (length(hex)=0) then hex:='00';
  if (length(hex)=1) then hex:=concat('0' + hex);
  hexstr2byte:=hexchar2byte(hex[1])*multiplier+hexchar2byte(hex[2]);
end;

function byte2hexstr(hex:byte):string;
begin
  byte2hexstr:='';
  if ((hex div 16) >=10) then byte2hexstr:=byte2hexstr+char((hex div 16)+55)
  else byte2hexstr:=byte2hexstr+char((hex div 16)+48);
  if ((hex mod 16) >=10) then byte2hexstr:=byte2hexstr+char((hex mod 16)+55)
  else byte2hexstr:=byte2hexstr+char((hex mod 16)+48);
end;

function byte2binstr(bin:byte;split:boolean):string;
var
    i:integer;
begin
  byte2binstr:='';
  for i:=0 to 7 do
   begin
     byte2binstr:=toString(Integer(bin mod 2)) + byte2binstr;
     bin:=bin div 2;
     if (i=3) and split then byte2binstr:=' '+byte2binstr;
   end;
end;

// =========================================
//              BARE NAVIGATION
// =========================================
procedure MoveDown(lines:integer);
begin
  if lines>0 then
   begin
     if ((select[level]+lines)<maxdisplay[level]) then
        // normal move
        select[level]:=select[level]+lines
     else
      begin
        // move beyond visible field
        lines:=lines-(maxdisplay[level]-select[level]);
        select[level]:=maxdisplay[level];
       end;
     if (lines>0) and (select[level]=maxdisplay[level]) and (maxdisplay[level]<listlen[level]) then
      begin
      // scroll
        scroll[level]:=scroll[level]+lines;
        if scroll[level] > (listlen[level]-maxdisplay[level]) then scroll[level]:=(listlen[level]-maxdisplay[level]);
      end;
  end;
end;

procedure MoveUp(lines:integer);
begin
  if lines>0 then
   begin
     if ((select[level]-lines)>0) then
       // move
       select[level]:=select[level]-lines
     else
       begin
       // move beyond visible field
        lines:=lines-select[level];
        select[level]:=0;
       end;
     if (lines>0) and (select[level]=0) and (scroll[level]>=0) then
       // scroll
       begin
         scroll[level]:=scroll[level]-lines;
         if scroll[level] < 0 then scroll[level]:=0;
       end;
   end;
end;

procedure MoveRight();
begin
  if level=3 then level:=1
  else level:=level+1;
end;

procedure MoveLeft();
begin
  if level=1 then level:=3
  else level:=level-1;
end;


// =========================================
//                 INPUT / OUTPUT
// =========================================

function openFile(filename:String) : boolean;
var
  status:integer;
begin
  assign(exefile,filename);
  {$I-}
  reset(exefile,1);
  {$I+}
  status:=IOResult;
  if status<>0 then
   begin
    writeln('Error opening "',filename,'".');
    openFile:=false;
   end
  else
   begin
    openFile:=true;
   end;
end; {openFile}

procedure closeFile();
begin
  close(exefile);
  {$I+}
end; {closeFile}

function readByte(address:Integer):byte;
var
  actual:word;
begin
  if filesize(exefile) >= address then
  begin
   seek(exefile,address);
   blockread (exefile,readByte,1,actual);
  end;
end;

// converts big-endian to little-endian
function readBytes(address:integer;nrofbytes:byte):fourbyte;
var i:byte;
begin
  nrofbytes:=min(4,nrofbytes);
  nrofbytes:=max(1,nrofbytes);
  for i:=0 to 3 do
    readBytes[i]:=0;
  for i:=3 downto (4-nrofbytes) do
   begin
     readBytes[i]:=readByte(address);
     address:=address+1;
   end;
end;

function readBytesInt(address:integer;nrofbytes:byte):integer;
begin
  nrofbytes:=max(1,nrofbytes);
  readBytesInt:=fourbyte2int(readBytes(address,nrofbytes),nrofbytes);
end;

procedure writeByte(address:Integer;data:byte);
var
  actual:word;
begin
  seek(exefile,address);
  blockwrite(exefile,data,1,actual);
end;


// converts little-endian to big-endian
procedure writeBytes(address:Integer;data:fourbyte;nrofbytes:byte);
var
  i:byte;
begin
  nrofbytes:=min(4,nrofbytes);
  nrofbytes:=max(1,nrofbytes);
  for i:=3 downto (4-nrofbytes) do
   begin
     writeByte(address,data[i]);
     address:=address+1;
   end;
end;

procedure writeBytesInt(address,data:Integer;nrofbytes:byte);
begin
  nrofbytes:=max(1,nrofbytes);
  writeBytes(address,int2fourbyte(data),nrofbytes);
end;


// =========================================
//              DATA & OFFSETS
// =========================================

function getDataLen(opttype:integer):integer;
begin
  // DATA TYPE LIST - Defines length for each data type. VERY important.
  case opttype of
    -1 : getDataLen:=0;                                                            // Safety value for empty list item.
     0 : getDataLen:=2;                                                            // 2-byte boolean
     1 : getDataLen:=1;                                                            // signed byte
     2 : getDataLen:=2;                                                            // 2-byte
     3 : getDataLen:=4;                                                            // 4-byte (REF)
     4 : getDataLen:=1;                                                            // owners
     5 : getDataLen:=2;                                                            // command
     6 : getDataLen:=2;                                                            // movement type
     7 : getDataLen:=2;                                                            // weapon type
     8 : getDataLen:=2;                                                            // foundation
     9 : getDataLen:=2;                                                            // decay factor
    10 : getDataLen:=4;                                                            // prerequisites
    11 : getDataLen:=2;                                                            // sounds
    12 : getDataLen:=0;                                                            // bit switch 1/8
    13 : getDataLen:=0;                                                            // bit switch 2/8
    14 : getDataLen:=0;                                                            // bit switch 3/8
    15 : getDataLen:=0;                                                            // bit switch 4/8
    16 : getDataLen:=0;                                                            // bit switch 5/8
    17 : getDataLen:=0;                                                            // bit switch 6/8
    18 : getDataLen:=0;                                                            // bit switch 7/8
    19 : getDataLen:=1;                                                            // bit switch 8/8  ; Bit switches must ALWAYS be used in groups of 8. Last one adds the size.
    20 : getDataLen:=2;                                                            // percentages
    21 : getDataLen:=2;                                                            // music
    22 : getDataLen:=2;                                                            // character
    23 : getDataLen:=2;                                                            // palace special abilities
    24 : getDataLen:=2;                                                            // SHP Graphics
    25 : getDataLen:=2;                                                            // unit display modes
    26 : getDataLen:=2;                                                            // action interrupt modes
    27 : getDataLen:=2;                                                            // sidebar modes
    28 : getDataLen:=2;                                                            // voc sounds
    29 : getDataLen:=1;                                                            // parent PAK
    30 : getDataLen:=1;                                                            // file type
    31 : getDataLen:=4;                                                            // structure animation
    32 : getDataLen:=2;                                                            // structure graphics set
  end;
end;

function getDataLen(typeindex,optindex:integer):integer;
var
    optslist:lev3lst;
begin
  optslist:=TypeOptsList[typeindex];
  getDataLen:=getDataLen(optslist[optindex].typeid)
end;

function getListLen(typeindex,toindex:integer):integer;
var i:integer;
    optslist:lev3lst;
begin
  optslist:=TypeOptsList[typeindex];
  getListLen:=0;
  for i:=0 to toindex-1 do
  begin
    getListLen:=getListLen+getDataLen(optslist[i].typeid);
  end;
end;

function getAddress(typeindex,unitindex,optindex:integer):integer ;
var typeoptsOffset,optslistLen:integer;
begin
  optslistLen:=optsListlengths[typeindex];
  typeoptsOffset:=typeOffset[typeindex][gamever];
  getAddress:=typeoptsOffset + (unitindex*getListLen(typeindex,optslistLen+1)) + getListLen(typeindex,optindex);
end;

// Get offset from reference
function getRefOffset(inputhex:fourbyte):integer;
var multiplier,i:integer;
begin
  getRefOffset:=0;
  multiplier:=1;
  for i:=3 downto 0 do
   begin
     getRefOffset:=getRefOffset+((inputhex[i]-refAddress[gamever][i])*multiplier);
     multiplier:=multiplier*256;
   end;
end;

// Get reference from offset
function getOffsetRef(inputint:integer):fourbyte;
var
    i:integer;
begin
  if inputint<>0 then
   begin
     getOffsetRef[0]:=refAddress[gamever][0];
     inputInt:=inputInt+refAddress[gamever][1]*256*256 + refAddress[gamever][2]*256 + refAddress[gamever][3];
     for i:=3 downto 1 do
      begin
        getOffsetRef[i]:=inputInt mod 256;
        inputInt:=inputInt div 256;
      end;
   end
  else
   for i:=3 downto 0 do
    begin
      getOffsetRef[i]:=0;
    end;
end;

// Reads zero-terminated string
function readString(address:integer):string;
var c:byte;
    i:integer;
begin
  i:=0;
  c:=$FF;
  readString:='';
  if address < filesize(exefile) then
   begin
    while (c<>0) and (i<100) do
     begin
       c:=readByte(address+i);
       if (c<>0) then readString:=concat(readString+char(c));
       i:=i+1;
     end;
   end
  else readString:='';
end;

// Gets offset from reference with zero and EOF correction.
function getRefAddress(inputhex:fourbyte):integer;
var
    blank:boolean;
    i:integer;
begin
  getRefAddress:=getRefOffset(inputhex);
  blank:=true;
  for i:=0 to 3 do
    if inputHex[i]<>0 then blank:=false;
  if blank then getRefAddress:=0;
  if (getRefAddress<0) or (getRefAddress> filesize(exefile)) then getRefAddress:=-1;
end;

function getRefAddress(typeindex,unitindex,optindex:integer):integer;
begin
  getRefAddress:=getRefAddress(readBytes(getAddress(typeindex,unitindex,optindex),4));
end;

// =========================================
//             DATA TYPE DISPLAY
// =========================================

function GetTypeDescr(id:integer): descr;
begin
  GetTypeDescr:=typedescr[id];
end;

function GetOptHelp(helpid:integer): bigdescr;
begin
  GetOptHelp:=optHelp[helpid];
end;


// Reads zero-terminated string defined by a reference
function getRefString(inputHex:fourbyte):string;
var
    blank:boolean;
    i:integer;
    ref:integer;
begin
  ref:=getRefOffset(inputhex);
  i:=0;
  blank:=true;
  for i:=0 to 3 do
    if inputHex[i]<>0 then blank:=false;

  if (ref>0) and not blank then getRefString:=readString(ref)
  else if blank then getRefString:='<no reference>'
  else getRefString:='<invalid ref>';
end;

function getRefString(typeindex,unitindex,optindex:integer):string;
begin
  getRefString:=getRefString(readBytes(getAddress(typeindex,unitindex,optindex),4));
end;

function getBytesString(nrofbytes:byte;inputhex:fourbyte;split:boolean):string;
var first,i:integer;
begin
  getBytesString:='';
  if nrofbytes<=4 then first:=4-nrofbytes
  else first:=3;
  for i:=first to 3 do
   begin
     getBytesString:=getBytesString + byte2hexStr(inputhex[i]);
     if (i<>3) and split then getBytesString:=getBytesString + ' ';
   end;
end;

function getBytesString(value:integer;split:boolean):string;
begin
     getBytesString:=getBytesString(4,int2fourbyte(value),split);
end;

function getBytesString(typeindex,unitindex,optindex:integer;split:boolean):string;
begin
  getBytesString:=getBytesString(max(1,getDataLen(typeindex,optindex)),readBytes(getAddress(typeindex,unitindex,optindex),getDataLen(typeindex,optindex)),split);
end;

function getBinString(nrofbytes:byte;inputhex:fourbyte;split:boolean):string;
var last,i:integer;
begin
  getBinString:='';
  if nrofbytes<=4 then last:=4-nrofbytes
  else last:=3;
  for i:=last to 3 do
   begin
     getBinString:=getBinString + byte2binStr(inputhex[i],split);
     if (i<>3) and split then getBinString:=getBinString + ' | ';
   end;
end;

function getBinString(typeindex,unitindex,optindex:integer;split:boolean):string;
begin
  getBinString:=getBinString(max(1,getDataLen(typeindex,optindex)),readBytes(getAddress(typeindex,unitindex,optindex),getDataLen(typeindex,optindex)),split);
end;

{
//unsigned, sinlge byte
function getByte(typeindex,unitindex,optindex:integer):byte;
begin
  getByte:=readByte(getAddress(typeindex,unitindex,optindex));
end;
}

//signed
function getBytes(typeindex,unitindex,optindex:integer):integer;
begin
  getBytes:=readBytesInt(getAddress(typeindex,unitindex,optindex),getDataLen(typeindex,optindex));
end;

//signed
function getBytes(typeindex,unitindex,optindex:integer;nrofbytes:byte):integer;
begin
  getBytes:=readBytesInt(getAddress(typeindex,unitindex,optindex),nrofbytes);
end;

// ==================
// TYPE-SPECIFIC DATA
// ==================

// get a name string of one of the main lists
function BasicType(unitindex,typeindex:integer):string;
begin
  if unitindex=-1 then BasicType:='None'
  else
  begin
    if (unitindex>=typeListLen[typeindex][gamever]) then BasicType:='<Invalid>'
    else if (refoption[typeindex] < 0) then BasicType:=toString(unitindex)
    else BasicType:=getRefString(typeindex,unitindex,refoption[typeindex]);
  end;
end;

// allows extra parameter to determine where to cut off the string.
function getValuesStr(typeindex,unitindex,optindex:integer;vallist:array of values;docutoff:boolean;cutoff:integer;ignoreUnkn,showvalue:boolean ):string;
var
  data,i:integer;
begin
  data:=getBytes(typeindex,unitindex,optindex);

  if ignoreUnkn then getValuesStr:=toString(data)
  else getValuesStr:='<Unknown>';
  for i:=0 to high(vallist) do
    if data=vallist[i].val then
      getValuesStr:=vallist[i].txt;

  if (showvalue) then
    getValuesStr:=toString(data) + ' - ' + getValuesStr;
  if docutoff then
    getValuesStr:=Copy(getValuesStr,1,cutoff);
end;

function getValuesStr(typeindex,unitindex,optindex:integer;vallist:array of values;showvalue:boolean):string;
begin
  getValuesStr:=getValuesStr(typeindex,unitindex,optindex,vallist,false,0,false,showvalue);
end;

function getValuesStr(typeindex,unitindex,optindex:integer;vallist:array of values;ignoreUnkn,showvalue:boolean):string;
begin
  getValuesStr:=getValuesStr(typeindex,unitindex,optindex,vallist,false,0,ignoreUnkn,showvalue);
end;

function getValuesStr(typeindex,unitindex,optindex:integer;vallist:array of values;docutoff:boolean;cutoff:integer;showvalue:boolean):string;
begin
    getValuesStr:=getValuesStr(typeindex,unitindex,optindex,vallist,docutoff,cutoff,false,showvalue)
end;

function getPercentageStr(typeindex,unitindex,optindex:integer):string;
var
  data,percdata:integer;
begin
  data:=getBytes(typeindex,unitindex,optindex);
  getPercentageStr:=toString(data) + '/256';
  percdata:=data*100 + 49;
  percdata:=percdata DIV 256;
  getPercentageStr:=getPercentageStr + ' (' + toString(percdata) + '%)';
  // NO LONGER DISPLAYED - full info above is more useful for editing.
  // Full list is now only used for quick selection.
  //for i:=0 to high(percentages) do
  // if data=percentages[i].val then getPercentageStr:=percentages[i].txt;
end;

function getGraphicsStr(typeindex,unitindex,optindex:integer;showindex:boolean):string;
var
  i:integer;
begin
  i:=getBytes(typeindex,unitindex,optindex);
  if i=-1 then getGraphicsStr:='None'
  else
  begin
    if ((gamever=0) or (gamever=1)) then
    begin
      if (i>=0) and (i<=high(graphicsLo)) then
        getGraphicsStr:=graphicsLo[i]
      else getGraphicsStr:='<Invalid>';
    end
    else
    begin
      if (i>=0) and (i<=high(graphicsHi)) then
        getGraphicsStr:=graphicsHi[i]
      else getGraphicsStr:='<Invalid>';
    end;
    if showindex then getGraphicsStr:=tostring(i) + ' - ' + getGraphicsStr;
  end;
end;

function readPrerequisites(typeindex,unitindex,optindex:integer):boollist;
var
    val,i,j:integer;
begin
  for i:=0 to 31 do readPrerequisites[i]:=false;
  val:=0;
  for i:=0 to max(0,(GetDataLen(typeindex,optindex)-1)) do
   begin
     val:=readByte(getAddress(typeindex,unitindex,optindex)+i);
     for j:=0 to 7 do
      begin
        if (val mod 2) = 1 then readPrerequisites[i*8+j]:=true;
        val:=val div 2;
      end;
   end;
end;

procedure writePrerequisites(p:boollist;typeindex,unitindex,optindex:integer);
var
    modifier,i,j:integer;
    val:byte;
begin
  val:=0;
  for i:=0 to max(0,(GetDataLen(typeindex,optindex)-1)) do
   begin
     modifier:=1;
     val:=0;
     for j:=0 to 7 do
      begin
        if p[i*8+j] then val:=val+modifier;
        modifier:=modifier*2;
      end;
     writeByte(getAddress(typeindex,unitindex,optindex)+i,val);
   end;
end;

// Does smart abbreviation to shorten the structure strings to 4 characters
function getPrerequisitestr(typeindex,unitindex,optindex:integer;shorten:boolean):string;
var
    b:boollist;
    i,active:integer;
begin
  b:=readPrerequisites(typeindex,unitindex,optindex);
  getPrerequisitestr:='';
  active:=0;
  for i:=0 to typeListLen[1][gamever]-1 do
      if b[i] then
      begin
        if (active=0) then
            getPrerequisitestr:=BasicType(i,1) + ','
        else if (active=1) then
        begin
          if shorten then
            getPrerequisitestr:=smartAbbrev(copy(getPrerequisitestr,1,length(getPrerequisitestr)-1)) + ','
                         + smartAbbrev(BasicType(i,1)) + ','
          else
            getPrerequisitestr:=getPrerequisitestr + BasicType(i,1) + ','
        end
        else
        begin
          if shorten then
            getPrerequisitestr:=getPrerequisitestr + smartAbbrev(BasicType(i,1)) + ','
          else
            getPrerequisitestr:=getPrerequisitestr + BasicType(i,1) + ','
        end;
        active:=active+1;
      end;
  if active>0 then
  begin
    getPrerequisitestr:=copy(getPrerequisitestr,1,length(getPrerequisitestr)-1);
    if shorten and (length(getPrerequisitestr)>19) then getPrerequisitestr:=concat(copy(getPrerequisitestr,1,17)+'..')
  end
  else getPrerequisitestr:='(none)';
end;

// shortens each owner string to 2 characters
function getOwnerstr(typeindex,unitindex,optindex:integer;shorten:boolean):string;
var
    b:boollist;
    i,active:integer;
begin
  b:=readPrerequisites(typeindex,unitindex,optindex);
  getOwnerstr:='';
  active:=0;
  for i:=0 to typeListLen[2][gamever]-1 do
      if b[i] then
      begin
        if (active=0) then
            getOwnerstr:=BasicType(i,2) + ','
        else if (active=1) then
        begin
          if shorten then
            getOwnerstr:=copy(getOwnerstr,1,2) + ','
                         + copy(BasicType(i,2),1,2) + ','
          else
            getOwnerstr:=getOwnerstr + BasicType(i,2)+ ','
        end
        else
        begin
          if shorten then
            getOwnerstr:=getOwnerstr + copy(BasicType(i,2),1,2) + ','
          else
            getOwnerstr:=getOwnerstr + BasicType(i,2) + ','
        end;
        active:=active+1;
      end;
  if active>0 then getOwnerstr:=copy(getOwnerstr,1,length(getOwnerstr)-1)
  else getOwnerstr:='(none)';
end;

function readSwitchBoolean(typeindex,unitindex,optindex,bitindex:integer):boolean;
var
    val:byte;
begin
    val:=readBytesInt(getAddress(typeindex,unitindex,optindex),1);
    readSwitchBoolean:=((val and (byte(1) shl bitindex)) > 0);
end;

procedure writeSwitchBoolean(value:boolean;typeindex,unitindex,optindex,bitindex:integer);
var
    val:byte;
begin
    val:=readBytesInt(getAddress(typeindex,unitindex,optindex),1);
    if value then val := val or      (word(1) shl bitindex)
    else          val := val and not (word(1) shl bitindex);
    writeByte(getAddress(typeindex,unitindex,optindex),val);
end;

function getSwitchBooleanstr(typeindex,unitindex,optindex,bitindex:integer):string;
var
    val:boolean;
begin
  val:=readSwitchBoolean(typeindex,unitindex,optindex,bitindex);
  if not HexDisplay then getSwitchBooleanstr:=booleans[word(val)].txt
  else getSwitchBooleanstr:=(toString(word(val)));
end;


// for all anim types
function readAnimScriptRef(typeindex,unitindex,optindex:integer):integer;
begin
  readAnimScriptRef:=readBytesInt(getAddress(typeindex,unitindex,optindex)+2,2);
end;

function GetAnimScriptLine(reference,line:integer): scriptLine;
var
  scriptcode:fourbyte;
begin
  reference:=reference*$10 + refHeader[gamever];
  scriptcode:=readBytes(reference+line*2,2);
  GetAnimScriptLine.command:=scriptcode[2] div $10;
  GetAnimScriptLine.argument:=(scriptcode[2] mod $10)*$100 + scriptcode[3];
  if GetAnimScriptLine.argument > $800 then
       GetAnimScriptLine.argument:=($1000-GetAnimScriptLine.argument)*-1;
end;

function getAnimScriptEnd(reference:integer; scriptcodes: array of scriptvalues): integer;
var
  lineNr:integer;
  animScript: scriptLine;
begin
  if reference=0 then getAnimScriptEnd:=-1
  else
  begin
    lineNr:=0;
    Repeat
      animScript:=GetAnimScriptLine(reference,lineNr);
      lineNr:=lineNr+1;
    until ((animScript.command>scriptcodes[high(scriptcodes)].val) or (scriptcodes[animScript.Command].isEnd));
    getAnimScriptEnd:=lineNr-1;
  end;
end;

function getAnimScriptEnd(typeindex,unitindex,optindex:integer; scriptcodes: array of scriptvalues): integer;
begin
  getAnimScriptEnd:=
        getAnimScriptEnd(readAnimScriptRef(typeindex,unitindex,optindex),scriptcodes);
end;

function readAnimScriptLineStr(reference,line:integer; scriptcodes: array of scriptvalues;shortdesc:boolean): String;
var
  animScript: scriptLine;
begin
  if reference=0 then readAnimScriptLineStr:=''
  else
  begin
    animScript:=GetAnimScriptLine(reference,line);
    if (shortdesc) then readAnimScriptLineStr:=scriptcodes[animScript.command].shorttxt
    else                readAnimScriptLineStr:=scriptcodes[animScript.command].longtxt + '   ';
    if scriptcodes[animScript.command].hasArg then
       readAnimScriptLineStr:=readAnimScriptLineStr + toString(abs(animScript.argument));
  end;
end;

function readAnimScriptLineStr(typeindex,unitindex,optindex,line:integer; scriptcodes: array of scriptvalues; shortdesc:boolean): String;
begin
  readAnimScriptLineStr:=
        readAnimScriptLineStr(readAnimScriptRef(typeindex,unitindex,optindex),line,scriptcodes,shortdesc);
end;

function getAnimScriptStr(typeindex,unitindex,optindex:integer; scriptcodes: array of scriptvalues):string;
var
  i,scriptEnd:integer;
  scriptLine: String;
begin
  getAnimScriptStr:='';
  scriptEnd:=getAnimScriptEnd(typeindex,unitindex,optindex,scriptcodes);
  scriptLine:='';
  i:=0;
  repeat
    scriptLine:=readAnimScriptLineStr(typeindex,unitindex,optindex,i,scriptcodes,true);
    i:=i+1;
    if (scriptLine<>'') then
      getAnimScriptStr:=getAnimScriptStr+scriptLine+' ';
  until (i>scriptEnd) or (scriptLine='');
  if (getAnimScriptStr='') then getAnimScriptStr:='None';
end;

function getDataStr(typeindex,unitindex,optindex:integer;shorten:boolean):string;
begin
  getDataStr:='';
  // DATA TYPE LIST - Gets correct strings to display in second column of 3rd list
  case TypeOptsList[typeindex][optindex].typeid of
     0 : getDataStr:=getValuesStr(typeindex,unitindex,optindex,booleans,not shorten);             // 2-byte boolean
     1 : getDataStr:=tostring(getBytes(typeindex,unitindex,optindex));                            // signed byte
     2 : getDataStr:=toString(getBytes(typeindex,unitindex,optindex));                            // 2-byte
     3 : getDataStr:=getRefString(typeindex,unitindex,optindex);                                  // 4-byte (REF)
     4 : getDataStr:=getOwnerstr(typeindex,unitindex,optindex,shorten);                           // owners
     5 : getDataStr:=BasicType(getBytes(typeindex,unitindex,optindex),3);                         // command
     6 : getDataStr:=BasicType(getBytes(typeindex,unitindex,optindex),-1);                        // movement type
     7 : getDataStr:=BasicType(getBytes(typeindex,unitindex,optindex),0);                         // weapon type
     8 : getDataStr:=getValuesStr(typeindex,unitindex,optindex,foundations,not shorten);          // foundation
     9 : getDataStr:=getValuesStr(typeindex,unitindex,optindex,decayFactors,true,false);          // decay factor
    10 : getDataStr:=getPrerequisitestr(typeindex,unitindex,optindex,shorten);                    // prerequisites
    11 : getDataStr:=getValuesStr(typeindex,unitindex,optindex,sounds,not shorten);               // sounds
    12 : getDataStr:=getSwitchBooleanstr(typeindex,unitindex,optindex,0);                         // bit switch 1/8
    13 : getDataStr:=getSwitchBooleanstr(typeindex,unitindex,optindex,1);                         // bit switch 2/8
    14 : getDataStr:=getSwitchBooleanstr(typeindex,unitindex,optindex,2);                         // bit switch 3/8
    15 : getDataStr:=getSwitchBooleanstr(typeindex,unitindex,optindex,3);                         // bit switch 4/8
    16 : getDataStr:=getSwitchBooleanstr(typeindex,unitindex,optindex,4);                         // bit switch 5/8
    17 : getDataStr:=getSwitchBooleanstr(typeindex,unitindex,optindex,5);                         // bit switch 6/8
    18 : getDataStr:=getSwitchBooleanstr(typeindex,unitindex,optindex,6);                         // bit switch 7/8
    19 : getDataStr:=getSwitchBooleanstr(typeindex,unitindex,optindex,7);                         // bit switch 8/8
    20 : getDataStr:=getPercentageStr(typeindex,unitindex,optindex);                              // percentages
    21 : getDataStr:=getValuesStr(typeindex,unitindex,optindex,music,not shorten);                // music
    22 : getDataStr:=char(getBytes(typeindex,unitindex,optindex,1));                              // character
    23 : getDataStr:=getValuesStr(typeindex,unitindex,optindex,PalaceSpecials,false);             // palace special abilities
    24 : getDataStr:=getGraphicsStr(typeindex,unitindex,optindex,not shorten);                    // SHP Graphics
    25 : getDataStr:=getValuesStr(typeindex,unitindex,optindex,displayModes,false);               // unit display modes
    26 : getDataStr:=getValuesStr(typeindex,unitindex,optindex,interruptModes,not shorten);       // action interrupt modes
    27 : getDataStr:=getValuesStr(typeindex,unitindex,optindex,sidebarmodes,shorten,17,false);    // sidebar modes
    28 : getDataStr:=getValuesStr(typeindex,unitindex,optindex,vocsounds,shorten,12,not shorten); // voc sounds
    29 : getDataStr:=BasicType(getBytes(typeindex,unitindex,optindex),4);                         // parent PAK
    30 : getDataStr:=getValuesStr(typeindex,unitindex,optindex,fileTypes,false);                  // file type
    31 : getDataStr:=getAnimScriptStr(typeindex,unitindex,optindex,structAnim);                   // structure animation
    32 : getDataStr:=getValuesStr(typeindex,unitindex,optindex,structureGraphics,not shorten);    // structure graphics set
  end;
  //lev3data normally contains strings of 20 chars, but in the current display mode I use 19.
  if shorten then
    getDataStr:=Copy(getDataStr,1,19);
end;

function getDataStr(typeindex,unitindex,optindex:integer):string;
begin
  getDataStr:=getDataStr(typeindex,unitindex,optindex,true);
end;

function inputValue(inputstr:String;minval,maxval:integer):integer;
var charin: char;
    minlen,maxlen:integer;
    tempstr:string;
begin
   charin:=char(0);
   str(minval,tempstr);
   minlen:=Length(tempstr);
   str(maxval,tempstr);
   maxlen:=Length(tempstr);
   write(inputstr);
   while ((charin<>keymap.esc) and (charin<>keymap.F2) and (charin<>'b') and (charin<>keymap.F3) and (charin<>'x') and (charin<>keymap.F4) and (charin<>'d') and (charin<>keymap.enter)) do
   begin
    charin:=ReadKey();
    if ((byte(charin)=45) and (Length(inputstr)=0) and (minval<0))
        or ((byte(charin)>=48) and (byte(charin)<=57)
          and (    ((Length(inputstr)<minlen) and (Copy(inputstr,1,1)='-'))
                or ((Length(inputstr)<maxlen) and (Copy(inputstr,1,1)<>'-'))
              )
       ) then
     begin
       inputstr:=inputstr+charin;
       write(charin);
     end
    else if (charin=keymap.back) and (Length(inputstr)>0) then
     begin
       inputstr:=Copy(inputstr, 1, (Length(inputstr)-1));
       write(keymap.back);
       write('_');
       write(keymap.back);
     end;
   end;
   val(inputstr,inputvalue);
   errormsg:='';
   if ((charin=keymap.esc) or (charin=keymap.F2) or (charin='b') or (charin=keymap.F3) or (charin='x') or (charin=keymap.F4) or (charin='d')) then errormsg:='Canceled'
   else if (inputvalue>maxval) then errormsg:='Value too large!'
   else if (inputvalue<minval) then errormsg:='Value too small!'
end; {inputValue}

function inputValue(minval,maxval:integer):integer;
begin
  inputValue:=inputValue('',minval,maxval);
end;

function inputChar(input:char):char;
var charin: char;
begin
   charin:=input;
   inputChar:=input;
   write(charin);
   while ((charin<>keymap.esc) and (charin<>keymap.F2) and (charin<>keymap.F3) and (charin<>keymap.F4) and (charin<>keymap.enter)) do
   begin
    charin:=ReadKey();
    if ( (byte(charin)>=65) and (byte(charin)<=90) ) or ( (byte(charin)>=97) and (byte(charin)<=122) ) then
     begin
       write(keymap.back);
       write(charin);
       inputChar:=charin;
     end
   end;
   errormsg:='';
   if ((charin=keymap.esc) or (charin=keymap.F2) or (charin=keymap.F3) or (charin=keymap.F4)) then errormsg:='Canceled'
end; {inputChar}

function inputHexBytes(inputstr:String;nrofbytes:byte):fourbyte;
var charin: char;
    i:integer;
begin
   for i:=0 to 3 do
     inputHexBytes[i]:=0;
   if nrofbytes>4 then nrofbytes:=4;
   for i:=1 to length(inputstr) do
     begin
      write(inputstr[i]);
      if (i<>0) and (i mod 2=0) and (i<(length(inputstr))) then write(' ');
     end;
   charin:=char(0);
   while ((charin<>keymap.esc) and (charin<>keymap.F2) and (charin<>keymap.F3) and (charin<>keymap.F4) and (charin<>'x') and (charin<>keymap.enter)) do
   begin
    charin:=ReadKey();
    if (byte(charin)>=97) and (byte(charin)<=102) then charin:=char(byte(charin)-32);
    if (((byte(charin)>=48) and (byte(charin)<=57)) or ((byte(charin)>=65) and (byte(charin)<=70)))
       and (length(inputstr)<(nrofbytes*2)) then
     begin
       inputstr:=inputstr+charin;
       write(charin);
       if (length(inputstr)>0) and ((length(inputstr) mod 2)=0) and (length(inputstr)<(nrofbytes*2))then write(' ');
     end
    else if (charin=keymap.back) and (Length(inputstr)>0) then
     begin
       if ((length(inputstr) mod 2)=0) and (length(inputstr)<(nrofbytes*2)) then write(keymap.back);
       inputstr:=Copy(inputstr, 1, (Length(inputstr)-1));
       write(keymap.back);
       write('_');
       write(keymap.back);
     end;
   end;
   while (length(inputstr)<(nrofbytes*2)) do
    begin
      inputstr:=inputstr+'0';
      write('0');
      if (length(inputstr)>0) and ((length(inputstr) mod 2)=0) then write(' ');
    end;
   while (length(inputstr)<(4*2)) do
    inputstr:='0'+inputstr;
   for i:=0 to 3 do
    begin
     inputhexbytes[i]:=hexstr2byte(copy(inputstr,1+i*2,2));
    end;
   if ((charin=keymap.esc) or (charin=keymap.F2) or (charin=keymap.F3) or (charin=keymap.F4) or (charin='x')) then errormsg:='Canceled'
   else errormsg:='';
end;

// =========================================
//              GENERAL LAYOUT
// =========================================

procedure TextCol(lev,i:integer);
begin
  if      (i= select[lev]) and (level= lev) then begin TextColor(activeitemcolor);   TextBackground(activeitembgcolor);   end
  else if (i= select[lev]) and (level<>lev) then begin TextColor(inactiveitemcolor); TextBackground(inactiveitembgcolor); end
  else if (i<>select[lev]) and (level= lev) then begin TextColor(activelevcolor);    TextBackground(activelevbgcolor);    end
  else if (i<>select[lev]) and (level<>lev) then begin TextColor(inactivelevcolor);  TextBackground(inactivelevbgcolor);  end;
end;

procedure ResetCol();
begin
  TextColor(activelevcolor);
  TextBackground(activelevbgcolor);
end;

procedure drawLineV(x,y,len:integer; c:char);
var count:integer;
begin
   for count:=0 to (len-1) do
    begin
      gotoxy(x,y+count);
      write(c);
    end;
end;

procedure drawLineH(x,y,len:integer; c:char);
var count:integer;
begin
  gotoxy(x,y);
  for count:=0 to len-1 do write(c);
end;

procedure clearBlock(x,y,w,h:integer);
var count:integer;
begin
  for count:=0 to h-1 do
   begin
     gotoxy(x,y+count);
     drawLineH(x,y+count,w,' ');
   end;
end;

// x-coord, y-coord, width, height, line in middle, draw as active frame, clear inside
procedure drawFrame(x,y,w,h,m:integer; active,fill:boolean );
var charset:integer;
begin
  if active then charset:=2
  else           charset:=1;
  gotoxy(x,y);
  write(char(framechar[charset,1]));
  gotoxy(x+w-1,y);
  write(char(framechar[charset,2]));
  gotoxy(x,y+h-1);
  write(char(framechar[charset,3]));
  gotoxy(x+w-1,y+h-1);
  write(char(framechar[charset,4]));
  drawLineH(x+1,y,w-2,char(framechar[charset,5]));
  drawLineH(x+1,y+h-1,w-2,char(framechar[charset,5]));
  drawlineV(x,y+1,h-2,char(framechar[charset,6]));
  drawlineV(x+w-1,y+1,h-2,char(framechar[charset,6]));
  if fill then clearBlock(x+1,y+1,w-2,h-2);
  if (m>1) then
   begin
     gotoxy(x+m-1,y);
     write(char(framechar[charset,7]));
     gotoxy(x+m-1,y+h-1);
     write(char(framechar[charset,8]));
     drawLineV(x+m-1,y+1,h-2,char(framechar[charset,6]));
   end;
  resetCursor();
end; {drawFrame}

procedure drawFrameArrows(l:integer);
var x,y1,y2,charset:integer;
    up,down:boolean;
begin
  x:=selectBoundaries[l][1]-1;
  y1:=selectBoundaries[l][2];
  y2:=selectBoundaries[l][4];
  // Is scrolled down
  up:=scroll[l] > 0;
  // Can scroll && hasn't scrolled to maximum
  down:=(maxdisplay[l]<listlen[l]) and (scroll[l] < (listlen[l]-maxdisplay[l]));
  if level=l then
  begin
    charset:=2;
    TextColor(activelevcolor);
  end
  else
  begin
    charset:=1;
    TextColor(inactivelevcolor);
  end;

  gotoxy(x,y1);
  if up then
    write(char(framechar[charset,9]))
  else
    write(' ');
  gotoxy(x,y2);
  if down then
    write(char(framechar[charset,10]))
  else
    write(' ');
  resetCol();
  resetCursor();
end;


procedure drawHeader();
begin
  gotoxy(1,1);
  drawLineH(1,1,80,char(framechar[2,5]));
  gotoxy(3,1);
  write(' '); write(editorname); write(' '); write(editorversion); write(' ');
  gotoxy(74-length(editorauthor),1);
  write(' by '); write(editorauthor); write(' ');
end;

procedure drawHeader2();
begin
  gotoxy(2,2);
  TextColor(inactivelevcolor);
  write('File: [' + gamenamestr + ']');
  gotoxy(max(1,(80-14-length(dunever[gamever]))),2);
  write('Dune ');
  TextColor(activelevcolor);
  write('V');
  TextColor(inactivelevcolor);
  write('ersion: ' + dunever[gamever]);
end;

procedure drawFooter();
begin
  gotoxy(2,25);
  TextColor(inactivelevcolor);
  write('[F1]=');
  TextColor(activelevcolor);
  write('H');
  TextColor(inactivelevcolor);
  write('ELP   [F2]/[F3]/[F4]=');
  TextColor(activelevcolor);
  write('B');
  TextColor(inactivelevcolor);
  write('IN/HE');
  TextColor(activelevcolor);
  write('X');
  TextColor(inactivelevcolor);
  write('/');
  TextColor(activelevcolor);
  write('D');
  TextColor(inactivelevcolor);
  write('EC EDIT   [F11]=');
  TextColor(activelevcolor);
  write('R');
  TextColor(inactivelevcolor);
  write('ESEARCH MODE   [F12]=');
  TextColor(activelevcolor);
  write('I');
  TextColor(inactivelevcolor);
  write('NFO');
end;

procedure drawHeaders();
begin
  TextBackground(inactivelevbgcolor);
  TextColor(inactivelevcolor);
  drawHeader();
  drawHeader2();
  drawFooter();
end;

// =========================================
//             SELECTION DISPLAY
// =========================================

function calcSelectBin(len:integer):integer;
var
 i:integer;
begin
  calcSelectBin:=len;
  for i:=0 to (len) do
   begin
     if (i mod 4 = 0) and (i<>0) then calcSelectBin:=calcSelectBin+1;
     if (i mod 8 = 0) and (i<>0) then calcSelectBin:=calcSelectBin+2;
   end;
end;

procedure drawSelectBin();
var
 i:integer;
begin
  gotoxy(selectBoundaries[4][1]+1,selectBoundaries[4][2]-2);
  for i:=0 to calcSelectBin(listlen[4]) do write(' ');
  gotoxy(selectBoundaries[4][1]+1+calcSelectBin(listlen[4])-calcSelectBin(select[4]+scroll[4]),selectBoundaries[4][2]-2);
  write(char(framechar[2,10]));
  gotoxy(selectBoundaries[4][1]+1,selectBoundaries[4][2]);
  for i:=0 to calcSelectBin(listlen[4]) do write(' ');
  gotoxy(selectBoundaries[4][1]+1+calcSelectBin(listlen[4])-calcSelectBin(select[4]+scroll[4]),selectBoundaries[4][2]);
  write(char(framechar[2,9]));
  resetCursor();
end;

procedure drawSel(l,pos:integer);
begin
  if maxdisplay[l] >=0 then
   begin
     TextCol(l,pos);
     case l of
       1 : drawLineH(selectBoundaries[l][1],selectBoundaries[l][2]+pos,selectionLengths[l],' ');
       2 : drawLineH(selectBoundaries[l][1],selectBoundaries[l][2]+pos,selectionLengths[l],' ');
       3 : drawLineH(selectBoundaries[l][1],selectBoundaries[l][2]+pos,selectionLengths[l],' ');
       4 : drawLineH(selectBoundaries[l][1],selectBoundaries[l][2]+pos,selectionLengths[l],' ');
     end;
     gotoxy(selectBoundaries[l][1]+1,selectBoundaries[l][2]+pos);
     case l of
       1 : write(mainlist[(pos+scroll[l])]);
       2 : write(lev2List[(pos+scroll[l])]);
       3 : begin
             write(lev3List[(pos+scroll[l])].text);
             gotoxy(selectBoundaries[3][1]+secondcolumn[3]-1,selectBoundaries[3][2]+pos);
             drawLineH(selectBoundaries[3][1]+secondcolumn[3]-1,selectBoundaries[3][2]+pos,secondcolumnSelection,' '); // second line
             gotoxy(selectBoundaries[3][1]+secondcolumn[3],selectBoundaries[3][2]+pos);
             write(lev3data[pos]);
           end;
       4 : if (listlen[4]>=0) then write(lev4List[(pos+scroll[l])]);
     end;
     ResetCol();
     resetCursor();
   end;
end;

procedure drawSelect(l,pos:integer);
begin
 if binEd and (level=4) then drawSelectBin()
 else drawSel(l,pos);
end;

procedure drawSelect(lev:integer);
begin
 if binEd and (level=4) then drawSelectBin()
 else drawSel(lev,select[lev]);
end;

procedure drawSelect();
begin
 if binEd and (level=4) then drawSelectBin()
 else drawSel(level,select[level]);
end;

procedure drawSelects();
var i:integer;
begin
  if level<>4 then
    for i:=1 to 3 do drawSelect(i)
  else drawSelect(4);
end;


// =========================================
//                 LIST DISPLAY
// =========================================

procedure makeValuesList(typeindex,unitindex,optindex:integer; vallist: array of values);
var
    val,i:integer;
begin
  val:=getBytes(typeindex,unitindex,optindex);
  listlen[4]:=high(vallist);
  for i:=0 to listlen[4] do
   begin
     if val=vallist[i].val then lev4List[i]:='* ' + uppercase(vallist[i].txt)
     else lev4List[i]:='  ' + vallist[i].txt;
   end;
end;

procedure MakePrerequisitesList(typeindex,unitindex,optindex,basetype:integer);
var
    i:integer;
    o:boollist;
begin
  o:=readPrerequisites(typeindex,unitindex,optindex);
  listlen[4]:=typeListLen[basetype][gamever]-1;
  for i:=0 to listlen[4] do
   begin
     if o[i] then lev4List[i]:='+ ' + uppercase(BasicType(i,basetype))
     else lev4List[i]:='  ' + BasicType(i,basetype);
   end;
end;

procedure makeBasicTypeList(typeIndex,unitindex,optindex,basetype:integer;HasEmpty:boolean);
var
    val,i: integer;
begin
  val:=getBytes(typeIndex,unitindex,optindex);
  listlen[4]:=typeListLen[basetype][gamever]-byte(not HasEmpty);
  if HasEmpty then
  begin
    lev4List[0]:='None';
    if (val=-1) then lev4List[0]:='* '+uppercase(lev4List[0])
    else             lev4List[0]:='  '+lev4List[0];
  end;
  for i:=0 to listlen[4] do
   begin
     if (i=val) then lev4List[i+byte(HasEmpty)]:='* '+uppercase(BasicType(i,basetype))
     else            lev4List[i+byte(HasEmpty)]:='  '+BasicType(i,basetype);
   end;
end;

procedure makeBasicTypeList(typeIndex,unitindex,optindex,basetype:integer);
begin
  makeBasicTypeList(typeIndex,unitindex,optindex,basetype,true);
end;

procedure makePAKList(typeIndex,unitindex,optindex:integer);
var
    val,i: integer;
begin
  val:=getBytes(typeIndex,unitindex,optindex);
  listlen[4]:=typeListLen[4][gamever]-1;
  i:=0;
  while i<listlen[4] do
   begin
     if (readBytesInt(getAddress(4,i,1),GetDataLen(4,1))=0) // check PAK ID value
//     if (pos('.PAK',uppercase(BasicType(i,4)))=0) // check filename extension
         then listlen[4]:=i-1;
     i:=i+1;
   end;
  for i:=0 to listlen[4] do
   begin
     if (i=val) then lev4List[i]:='* '+uppercase(BasicType(i,4))
     else            lev4List[i]:='  '+lowercase(BasicType(i,4));
   end;
end;

procedure makeGraphicsList(typeindex,unitindex,optindex:integer);
var
    val,i:integer;
begin
  val:=getBytes(typeindex,unitindex,optindex);
  if ((gamever=0) or (gamever=1)) then listlen[4]:=high(GraphicsLo)+1
  else                                 listlen[4]:=high(GraphicsHi)+1;
  lev4List[0]:='None';
  if (val=-1) then lev4List[0]:=' -1 * '+uppercase(lev4List[0])
  else             lev4List[0]:=' -1   '+lev4List[0];
  for i:=0 to listlen[4] do
   begin
     if ((gamever=0) or (gamever=1)) then 
     begin 
       if (i=val) then lev4List[i+1]:=tostring(i) + ' * ' + uppercase(GraphicsLo[i])
       else            lev4List[i+1]:=tostring(i) + '   ' + GraphicsLo[i];
     end
     else
     begin 
       if (i=val) then lev4List[i+1]:=tostring(i) + ' * ' + uppercase(GraphicsHi[i])
       else            lev4List[i+1]:=tostring(i) + '   ' + GraphicsHi[i];
     end;
     if (i<100) then lev4List[i+1]:='0'+lev4List[i+1];
     if (i<10)  then lev4List[i+1]:='0'+lev4List[i+1];
   end;
end;

procedure makeAnimScriptList(typeindex,unitindex,optindex:integer; scriptcodes: array of scriptvalues);
var
  address,i: integer;
  animScript: scriptLine;
begin
  address:=readAnimScriptRef(typeindex,unitindex,optindex);
  listlen[4]:=getAnimScriptEnd(typeindex,unitindex,optindex,scriptcodes);
  for i:=0 to listlen[4] do
   begin
    lev4List[i]:=readAnimScriptLineStr(address,i,scriptcodes,false);
   end;
  // For maybe allowing script editing later
  repeat
    i:=i+1;
    animScript:=GetAnimScriptLine(address,i);
    if ((animScript.command=defaultEmptyAnimScriptLine.command)
     and (animScript.argument=defaultEmptyAnimScriptLine.argument))
     then
     begin
     listlen[4]:=i;
     lev4List[i]:='[Available script space]';
     end;
  until ((animScript.command<>defaultEmptyAnimScriptLine.command)
       or (animScript.argument<>defaultEmptyAnimScriptLine.argument));
  if (listlen[4]=-1) then
  begin
   lev4List[0]:='[No script actions]';
   listlen[4]:=0;
  end;
end;

procedure makeSwitchBooleanList(typeindex,unitindex,optindex,bitindex:integer);
var
    b: boolean;
    i: integer;
begin
  b:=readSwitchBoolean(typeindex,unitindex,optindex,bitindex);
  maxdisplay[4]:=1;
  listlen[4]:=1;
  for i:=0 to listlen[4] do
   begin
     if integer(b)=booleans[i].val then lev4List[i]:=uppercase(booleans[i].txt)
     else                               lev4List[i]:=booleans[i].txt;
   end;
end;

procedure drawBinList(typeindex,unitindex,optindex:integer);
begin
  gotoxy(selectBoundaries[4][1]+1,selectBoundaries[4][2]-1);
  write(getBinString(typeindex,unitindex,optindex,true));
  gotoxy(selectBoundaries[4][1]+11,selectBoundaries[4][2]+2);
  write(getBytesString(typeindex,unitindex,optindex,true));
  resetCursor();
  ResetCol();
end;

// if maxdisplay[4] is -1 this function does nothing
// This function also adjusts the listlen if the list contains less items than the full length,
procedure drawLev4Select();
var
    i,last:integer;
begin
  if listlen[4]<maxdisplay[4] then last:=listlen[4]
  else last:=maxdisplay[4];
  for i:=0 to last do
   begin
     TextCol(4,i);
     drawLineH(selectBoundaries[4][1],selectBoundaries[4][2]+i,selectionLengths[4],' ');
     gotoxy(selectBoundaries[4][1]+1,selectBoundaries[4][2]+i);
     write(lev4List[(i+scroll[4])]);
   end;
  resetCursor();
  ResetCol();
end;


procedure drawLev4();
var
    typeindex,unitindex,optindex:integer;
begin
  typeindex:=select[1]+scroll[1];
  unitindex:=select[2]+scroll[2];
  optindex:=select[3]+scroll[3];
  if not binEd then
   begin
    // DATA TYPE LIST - Creates level 4 list for each data type
    // Fills the listlen[4] and lev4List variables.
    case TypeOptsList[typeindex][optindex].typeid of
       0 : makeValuesList(typeindex,unitindex,optindex,Booleans);                  // 2-byte boolean
       1 : listlen[4]:=-1;                                                         // signed byte
       2 : listlen[4]:=-1;                                                         // 2-byte
       3 : listlen[4]:=-1;                                                         // 4-byte (REF)
       4 : MakePrerequisitesList(typeindex,unitindex,optindex,2);                  // owners
       5 : makeBasicTypeList(typeindex,unitindex,optindex,3);                      // command
       6 : makeBasicTypeList(typeindex,unitindex,optindex,-1,false);               // movement type
       7 : makeBasicTypeList(typeindex,unitindex,optindex,0);                      // weapon type
       8 : makeValuesList(typeindex,unitindex,optindex,foundations);               // foundation
       9 : makeValuesList(typeindex,unitindex,optindex,decayFactors);              // decay factor
      10 : makePrerequisitesList(typeindex,unitindex,optindex,1);                  // prerequisites
      11 : makeValuesList(typeindex,unitindex,optindex,sounds);                    // sounds
      12 : makeSwitchBooleanList(typeindex,unitindex,optindex,0);                  // bit switch 1/8
      13 : makeSwitchBooleanList(typeindex,unitindex,optindex,1);                  // bit switch 2/8
      14 : makeSwitchBooleanList(typeindex,unitindex,optindex,2);                  // bit switch 3/8
      15 : makeSwitchBooleanList(typeindex,unitindex,optindex,3);                  // bit switch 4/8
      16 : makeSwitchBooleanList(typeindex,unitindex,optindex,4);                  // bit switch 5/8
      17 : makeSwitchBooleanList(typeindex,unitindex,optindex,5);                  // bit switch 6/8
      18 : makeSwitchBooleanList(typeindex,unitindex,optindex,6);                  // bit switch 7/8
      19 : makeSwitchBooleanList(typeindex,unitindex,optindex,7);                  // bit switch 8/8
      20 : makeValuesList(typeindex,unitindex,optindex,percentages);               // percentages
      21 : makeValuesList(typeindex,unitindex,optindex,music);                     // music
      22 : listlen[4]:=-1;                                                         // character
      23 : makeValuesList(typeindex,unitindex,optindex,palaceSpecials);            // palace special abilities
      24 : makeGraphicsList(typeindex,unitindex,optindex);                         // SHP Graphics
      25 : makeValuesList(typeindex,unitindex,optindex,displayModes);              // unit display modes
      26 : makeValuesList(typeindex,unitindex,optindex,interruptModes);            // action interrupt modes
      27 : makeValuesList(typeindex,unitindex,optindex,sidebarModes);              // sidebar modes
      28 : makeValuesList(typeindex,unitindex,optindex,vocsounds);                 // voc sounds
      29 : makePAKList(typeindex,unitindex,optindex);                              // parent PAK
      30 : makeValuesList(typeindex,unitindex,optindex,fileTypes);                 // file type
      31 : makeAnimScriptList(typeindex,unitindex,optindex,structAnim);            // structure animation
      32 : makeValuesList(typeindex,unitindex,optindex,structureGraphics);         // structure graphics set
    end;
    maxdisplay[4]:=selectBoundaries[4][1]-selectBoundaries[4][2];
    if listlen[4]<maxdisplay[4] then maxdisplay[4]:=listlen[4];
    drawLev4Select();
   end
  else drawBinList(typeindex,unitindex,optindex);
end;

procedure drawLev3data();
var i,last: integer;
//    showlist:array [0..19] of String[20];
begin
  if listlen[3]<maxdisplay[3] then last:=listlen[3]
  else last:=maxdisplay[3];
  for i:=0 to last do
  begin
    TextCol(3,i);
    if not HexDisplay then lev3data[i]:=getDataStr(select[1]+scroll[1],select[2]+scroll[2],i+scroll[3])
    else
      begin
        if (lev3list[i+scroll[3]].typeid >=12) and (lev3list[i+scroll[3]].typeid <=19) then
          lev3data[i]:=getDataStr(select[1]+scroll[1],select[2]+scroll[2],i+scroll[3])
        else
          lev3data[i]:=getBytesString(select[1]+scroll[1],select[2]+scroll[2],i+scroll[3],true);
      end;
  end;
  for i:=0 to last do
  begin
    TextCol(3,i);
    drawLineH(selectBoundaries[3][1]+secondcolumn[3]-1,selectBoundaries[3][2]+i,secondcolumnSelection,' ');
    gotoxy(selectBoundaries[3][1]+secondcolumn[3],selectBoundaries[3][2]+i);
    write(lev3data[i]);
  end;
  ResetCol();
  if last < (selectBoundaries[3][4]-selectBoundaries[3][2]) then
    for i:=last+1 to (selectBoundaries[3][4]-selectBoundaries[3][2]) do
    begin
      drawLineH(selectBoundaries[3][1]+secondcolumn[3]-1,selectBoundaries[3][2]+i,secondcolumnSelection,' ');
      gotoxy(selectBoundaries[3][1]+1,selectBoundaries[3][2]+i);
    end;
  resetCursor();
end;

procedure drawLev3();
var i,last: integer;
begin
  maxdisplay[3]:=min((selectBoundaries[3][4]-selectBoundaries[3][2]),listlen[3]);
  if listlen[3]<maxdisplay[3] then last:=listlen[3]
  else last:=maxdisplay[3];
  for i:=0 to last do
  begin
    TextCol(3,i);
    drawLineH(selectBoundaries[3][1],selectBoundaries[3][2]+i,selectionLengths[3],' ');
    gotoxy(selectBoundaries[3][1]+1,selectBoundaries[3][2]+i);
    write(lev3List[(i+scroll[3])].text);
  end;
  ResetCol();
  if last < (selectBoundaries[3][4]-selectBoundaries[3][2]) then
    for i:=last+1 to (selectBoundaries[3][4]-selectBoundaries[3][2]) do
    begin
      drawLineH(selectBoundaries[3][1],selectBoundaries[3][2]+i,selectionLengths[3],' ');
      gotoxy(selectBoundaries[3][1]+1,selectBoundaries[3][2]+i);
    end;
  drawLev3data();
end;

procedure drawLev2();
var i,last: integer;
begin
  maxdisplay[2]:=min((selectBoundaries[2][4]-selectBoundaries[2][2]),listlen[2]);
  if listlen[2]<maxdisplay[2] then last:=listlen[2]
  else last:=maxdisplay[2];
  for i:=0 to last do
  begin
    TextCol(2,i);
    drawLineH(selectBoundaries[2][1],selectBoundaries[2][2]+i,selectionLengths[2],' ');
    gotoxy(selectBoundaries[2][1]+1,selectBoundaries[2][2]+i);
    write(lev2List[(i+scroll[2])]);
  end;
  ResetCol();
  if last < (selectBoundaries[2][4]-selectBoundaries[2][2]) then
    for i:=last+1 to (selectBoundaries[2][4]-selectBoundaries[2][2]) do
    begin
      drawLineH(selectBoundaries[2][1],selectBoundaries[2][2]+i,selectionLengths[2],' ');
    end;
  resetCursor();
end;

procedure drawLev1();
var i,last: integer;
begin
  maxdisplay[1]:=min((selectBoundaries[1][4]-selectBoundaries[1][2]),listlen[1]);
  if listlen[1]<maxdisplay[1] then last:=listlen[1]
  else last:=maxdisplay[1];
  for i:=0 to last do
  begin
    TextCol(1,i);
    drawLineH(selectBoundaries[1][1],selectBoundaries[1][2]+i,selectionLengths[1],' ');
    gotoxy(selectBoundaries[1][1]+1,selectBoundaries[1][2]+i);
    write(mainlist[(i+scroll[1])]);
  end;
  ResetCol();
  if last < (selectBoundaries[1][4]-selectBoundaries[1][2]) then
    for i:=last+1 to (selectBoundaries[1][4]-selectBoundaries[1][2]) do
    begin
      drawLineH(selectBoundaries[2][1],selectBoundaries[2][2]+i,selectionLengths[2],' ');
    end;
  resetCursor();
end;

procedure drawList(l:integer);
begin
  case l of
   1 : drawLev1();
   2 : drawLev2();
   3 : drawLev3();
   4 : drawLev4();
  end;
  drawFrameArrows(l);
end;

procedure drawList();
begin
   drawList(level);
end;

procedure drawLists();
var i:integer;
begin
   for i:=1 to 3 do drawList(i);
end;

procedure hexdisplay_adaptlist2item(itemnumber:integer);
begin
  lev2List[itemnumber]:=copy(lev2List[itemnumber],1,13);
  while length(lev2List[itemnumber]) < 13 do lev2List[itemnumber]:=lev2List[itemnumber] + ' ';
  if (lev3list[select[3]+scroll[3]].typeid >=12) and (lev3list[select[3]+scroll[3]].typeid <=19) then
      lev2List[itemnumber]:=lev2List[itemnumber] + getDataStr(select[1]+scroll[1],itemnumber,select[3]+scroll[3])
  else
      lev2List[itemnumber]:=lev2List[itemnumber] + getBytesString(select[1]+scroll[1],itemnumber,select[3]+scroll[3],false);
end;

procedure updateLev2Lists();
var listtype,i:integer;
begin
  listtype:=select[1]+scroll[1];
  listlen[3]:=optsListlengths[listtype];
  lev3List:=TypeOptsList[listtype];
  listlen[2]:=typeListLen[listtype][gamever]-1;
  for i:=0 to listlen[2] do
    begin
      lev2List[i]:=BasicType(i,listtype);
      if HexDisplay then
        hexdisplay_adaptlist2item(i);
    end;
end;

procedure updateLists();
var i: integer;
begin
  for i:=2 to 3 do
    begin
      scroll[i]:=0;
      select[i]:=0;
    end;
  updateLev2Lists();
  for i:=2 to 3 do
    begin
      drawList(i);
      drawSelect(i);
    end;
end;

// =========================================
//                INPUT LAYOUT
// =========================================

procedure showinputInt(typeindex,unitindex,optindex,minval,maxval:integer);
var
    input,inputlength,x,y:integer;
    curval:String;
    typeinfo:descr;
begin
   typeinfo:=GetTypeDescr(lev3list[optindex].typeid);
   maxdisplay[4]:=0;
   listlen[4]:=-1;
   scroll[4]:=0;
   select[4]:=0;
   x:=selectBoundaries[4][1];
   y:=selectBoundaries[4][2]-2;
   inputlength:=20;
   if (typeinfo[2])<>'' then y:=y+1;
   gotoxy(x,y);
   write('Old value : ');
   curval:=toString(getBytes(typeindex,unitindex,optindex));
   write(curval);
   x:=x+2; y:=y+3; gotoxy(x,y);
   write('___________________');
   gotoxy(x,y);
   x:=x+inputlength+5;
   input:=inputValue(curval,minval,maxval);
   if length(errormsg)=0 then
    begin
      // SAVE
      writeBytesInt(getAddress(typeindex,unitindex,optindex),input,getDataLen(typeindex,optindex));
    end
   else if errormsg<> 'Canceled' then
    begin
      gotoxy(x,y);
      write(errormsg);
      resetCursor();
      cntin();
    end;
   resetCursor();
   level:=prevlev;
end;

procedure showinputInt(typeindex,unitindex,optindex:integer;signed:boolean);
var i,minval,maxval:integer;
begin
  minval:=-128;
  maxval:=0;
  for i:=2 to getDataLen(typeindex,optindex) do
    minval:=minval*256;
  if signed then maxval:=(minval+1)*-1
  else
   begin
     maxval:=((minval+1)*-2)+1;
     minval:=0;
   end;
  showinputInt(typeindex,unitindex,optindex,minval,maxval);
end;

procedure showinputInt2(typeindex,unitindex,optindex:integer);
var i,minval,maxval:integer;
begin
  minval:=-128;
  maxval:=0;
  for i:=2 to (max(1,getDataLen(typeindex,optindex))) do
    minval:=minval*256;
  maxval:=(minval+1)*-1;
  gotoxy(selectBoundaries[4][1],selectBoundaries[4][2]-3);
  write('Data range: ');
  write(minval,',',maxval);
  showinputInt(typeindex,unitindex,optindex,minval,maxval);
end;


procedure showinputOffset(typeindex,unitindex,optindex:integer);
var
    input:integer;
    curval:integer;
    ref:fourbyte;
    typeinfo:descr;
begin
  typeinfo:=GetTypeDescr(lev3list[optindex].typeid);
  maxdisplay[4]:=0;
  listlen[4]:=-1;
  scroll[4]:=0;
  select[4]:=0;
  if (typeinfo[2])<>'' then
    gotoxy(selectBoundaries[4][1],selectBoundaries[4][2]-1)
  else gotoxy(selectBoundaries[4][1],selectBoundaries[4][2]);
  write('Old value : ');
  curval:=getRefAddress(typeindex,unitindex,optindex);
  write(getBytesString(typeindex,unitindex,optindex,true));
  write(' (');
  if curval<>0 then write('offset '+ toString(curval))
  else write('blank');
  write(')');
  gotoxy(selectBoundaries[4][1],selectBoundaries[4][2]+3);
  write('WARNING - Don''t edit these unless you know');
  gotoxy(selectBoundaries[4][1],selectBoundaries[4][2]+4);
  write('          exactly what you''re doing!');
  gotoxy(selectBoundaries[4][1]+2,selectBoundaries[4][2]+1);
  write('___________________');
  gotoxy(selectBoundaries[4][1]+2,selectBoundaries[4][2]+1);
  input:=inputValue(toString(curval),0,filesize(exefile)-1);
  gotoxy(selectBoundaries[4][1]+32,selectBoundaries[4][2]+1);
  if length(errormsg)=0 then
   begin
     // SAVE
     ref:=getOffsetRef(input);
     gotoxy(selectBoundaries[4][1],selectBoundaries[4][2]+3);
     write('                                                 ');
     gotoxy(selectBoundaries[4][1],selectBoundaries[4][2]+3);
     write('New value : ');
     write(getBytesString(4,ref,true));
     if input<>0 then begin write(' (offset '); write(getRefAddress(ref)); write(')'); end
     else write(' (blank)');
     gotoxy(selectBoundaries[4][1],selectBoundaries[4][2]+4);
     write('                                                 ');
     gotoxy(selectBoundaries[4][1],selectBoundaries[4][2]+4);
     write('New string: ');
     if input<>0 then write('"');
     write(getRefString(ref));
     if input<>0 then write('"');
     gotoxy(selectBoundaries[4][1],selectBoundaries[4][2]+6);
     write('[ENTER]/[SPACE]: save     [ESC]: cancel');
     keyread:=ReadKey();
     if (keyread=keymap.ENTER) or (keyread=keymap.ENTER) then
       writeBytes(getAddress(typeindex,unitindex,optindex),ref,4);
     while keypressed do ReadKey(); // clear character buffer
   end
  else if errormsg<> 'Canceled' then
   begin
     write(errormsg);
     cntin();
   end;
  resetCursor();
  level:=prevlev;
end;

procedure showinputHex(typeindex,unitindex,optindex:integer);
var
    input:fourbyte;
begin
  maxdisplay[4]:=0;
  listlen[4]:=-1;
  scroll[4]:=0;
  select[4]:=0;
  gotoxy(selectBoundaries[4][1],selectBoundaries[4][2]-3);
  write('Old value : ' + getBytesString(typeindex,unitindex,optindex,true));
  gotoxy(selectBoundaries[4][1]+2,selectBoundaries[4][2]);
  input:=inputHexBytes(getBytesString(typeindex,unitindex,optindex,false),max(1,getDataLen(typeindex,optindex)));
  gotoxy(selectBoundaries[4][1]+32,selectBoundaries[4][2]);
  if length(errormsg)=0 then
    writeBytes(getAddress(typeindex,unitindex,optindex),input,getDataLen(typeindex,optindex));
  ResetCol();
  resetCursor();
  level:=prevlev;
end;


procedure showinputBin(typeindex,unitindex,optindex:integer);
begin
  binEd:=true;
  listlen[4]:=max(1,getDataLen(typeindex,optindex))*8-1;
  maxdisplay[4]:=listlen[4];
    scroll[4]:=0;
  // SPECIAL CODE FOR BIT SWITCH VALUES
  if (lev3list[optindex].typeid >=12) and (lev3list[optindex].typeid <=19) then
    select[4]:=lev3list[optindex].typeid-12
  else
    select[4]:=0;
  gotoxy(selectBoundaries[4][1],selectBoundaries[4][2]-3);
  write('Old value : ' + getBytesString(typeindex,unitindex,optindex,true));
  gotoxy(selectBoundaries[4][1],selectBoundaries[4][2]+2);
  write('New value:');
  gotoxy(selectBoundaries[4][1],selectBoundaries[4][2]-2);
  drawBinList(typeindex,unitindex,optindex);
  drawSelectBin();
end;

procedure showinputChar(typeindex,unitindex,optindex:integer);
var
    input:char;
begin
  maxdisplay[4]:=0;
  listlen[4]:=-1;
  scroll[4]:=0;
  select[4]:=0;
  gotoxy(selectBoundaries[4][1],selectBoundaries[4][2]-1);
  write('Old value : "' + char(getBytes(typeindex,unitindex,optindex,1))+'"');
  gotoxy(selectBoundaries[4][1]+2,selectBoundaries[4][2]+1);
  input:=inputChar(char(getBytes(typeindex,unitindex,optindex,1)));
  gotoxy(selectBoundaries[4][1]+32,selectBoundaries[4][2]+1);
  if length(errormsg)=0 then
    writeBytesInt(getAddress(typeindex,unitindex,optindex),byte(input),1);
  ResetCol();
  resetCursor();
  level:=prevlev;
end;

// ======================
// Show list instructions
// ======================

procedure showBasicList(typeindex,unitindex,optindex:integer;hasblank:boolean);
var
    val:integer;
begin
  val:=readBytesInt(getAddress(typeindex,unitindex,optindex),getDataLen(typeindex,optindex));
  if (getDataStr(typeindex,unitindex,optindex) <> '<Invalid>') and (val <> -1) then moveDown(val+byte(hasblank));
  drawLev4Select(); // resets view after scrolling
end;

procedure showBasicList(typeindex,unitindex,optindex:integer);
begin
  showBasicList(typeindex,unitindex,optindex,false);
end;

procedure showSwitchBooleanList(typeindex,unitindex,optindex,bitindex:integer);
var
    val:boolean;
begin
  val:=readSwitchBoolean(typeindex,unitindex,optindex,bitindex);
  moveDown(byte(val));
  drawLev4Select(); // resets view after scrolling
end;

procedure showValuesList(typeindex,unitindex,optindex:integer; vallist: array of values);
var
    scrolling,i,val,diff,diff2:integer;
begin
  val:=readBytesInt(getAddress(typeindex,unitindex,optindex),getDataLen(typeindex,optindex));
  scrolling:=-1;
  for i:=0 to high(vallist) do
    if val=vallist[i].val then scrolling:=i;
  if (scrolling <> -1) then moveDown(scrolling)
  // always assumes that the latest value in the list is the highest.
  else if (val > vallist[high(vallist)].val) then  moveDown(high(vallist))
  // current value is not in the list: jump to the item on the list with the closest value
  else if (val < vallist[high(vallist)].val) and (val > vallist[low(vallist)].val) then
  begin
    diff:=abs(val-vallist[0].val);
    scrolling:=0;
    for i:=0 to high(vallist) do
    begin
      diff2:=abs(val-vallist[i].val);
      if (diff2 < diff ) then
      begin
        diff:=diff2;
        scrolling:=i;
      end
    end;
    moveDown(scrolling)
  end;
  drawLev4Select(); // resets view after scrolling
end;

// =========================================
//                MAIN LAYOUT
// =========================================

procedure drawLevFrame(lvl:integer;active:boolean);
var
    clear:boolean;
begin
  TextBackground(activelevbgcolor);
  if lvl=4 then clear:=true
  else clear:=false;
  if level=lvl then
    TextColor(activelevcolor)
  else
    TextColor(inactivelevcolor);
  drawFrame(drawBoundaries[lvl][1],drawBoundaries[lvl][2],drawBoundaries[lvl][3],drawBoundaries[lvl][4],secondcolumn[lvl],active,clear);
  TextColor(activelevcolor);
end;

procedure drawLevFrame(lvl:integer);
begin
  case lvl of
   1 : drawLevFrame(lvl,level=1);
   2 : drawLevFrame(lvl,level=2);
   3 : drawLevFrame(lvl,level=3);
   4 : drawLevFrame(lvl,true);
  end;
end;

procedure drawLevFrame();
begin
  drawLevFrame(level);
end;

procedure drawLevFrames();
var i: integer;
begin
  for i:=1 to 3 do
   begin
     drawLevFrame(i);
   end;
end;

procedure clearWorkArea();
begin
  ClrScr();
  drawHeaders();
end;

procedure drawLayout4(edtype:integer);
var
    typeindex,unitindex,optindex:integer;
    typeinfo:descr;
begin
  typeindex:=select[1]+scroll[1];
  unitindex:=select[2]+scroll[2];
  optindex:=select[3]+scroll[3];
  typeinfo:=GetTypeDescr(lev3list[optindex].typeid);
  drawLevFrame(prevlev,true);
  drawList(prevlev);
  drawSelect(prevlev);
  drawLevFrame(4);
  gotoxy(selectBoundaries[4][1],selectBoundaries[4][2]-7);
  write('[');
  if edtype=1 then write('BIN ');
  if edtype=2 then write('HEX ');
  if edtype=3 then write('DEC ');
  write('EDIT]');
  gotoxy(selectBoundaries[4][1],selectBoundaries[4][2]-6);
  write('Section   : ');
  write(BasicType(unitindex,typeindex));
  gotoxy(selectBoundaries[4][1],selectBoundaries[4][2]-5);
  write('Option    : ');
  write(lev3list[optindex].text);
  gotoxy(selectBoundaries[4][1],selectBoundaries[4][2]-4);
  write('Address   : ');
  if ((edtype=1) OR (edtype=2)) then
     write(getBytesString(getAddress(typeindex,unitindex,optindex),false))
  else
     write(toString(getAddress(typeindex,unitindex,optindex)));
  if (edtype=0) then
   begin
     gotoxy(selectBoundaries[4][1],selectBoundaries[4][2]-3);
     write('Data type : ');
     gotoxy(selectBoundaries[4][1]+12,selectBoundaries[4][2]-3);
     write(typeinfo[1]);
     gotoxy(selectBoundaries[4][1]+12,selectBoundaries[4][2]-2);
     write(typeinfo[2]);
     gotoxy(17,10);
     maxdisplay[4]:=0;
     listlen[4]:=0;
     select[4]:=0;
     scroll[4]:=0;
     drawList();
     // DATA TYPE LIST - Gives extra instructions for showing each data type,
     //                  or opens special type-specific editor
     case lev3list[optindex].typeid of
       0 : showValuesList(typeindex,unitindex,optindex,booleans);                  // 2-byte boolean
       1 : showinputInt(typeindex,unitindex,optindex,true);                        // signed byte
       2 : showinputInt(typeindex,unitindex,optindex,true);                        // 2-byte
       3 : showinputOffset(typeindex,unitindex,optindex);                          // 4-byte (REF)
       4 : ; {no special show instructions needed}                                 // owners
       5 : showBasicList(typeindex,unitindex,optindex,true);                       // command
       6 : showBasicList(typeindex,unitindex,optindex,false);                      // movement type
       7 : showBasicList(typeindex,unitindex,optindex,true);                       // weapon type
       8 : showValuesList(typeindex,unitindex,optindex,foundations);               // foundation
       9 : showValuesList(typeindex,unitindex,optindex,decayFactors);              // decay factor
      10 : ; {no special show instructions needed}                                 // prerequisites
      11 : showValuesList(typeindex,unitindex,optindex,sounds);                    // sounds
      12 : showSwitchBooleanList(typeindex,unitindex,optindex,0);                  // bit switch 1/8
      13 : showSwitchBooleanList(typeindex,unitindex,optindex,1);                  // bit switch 2/8
      14 : showSwitchBooleanList(typeindex,unitindex,optindex,2);                  // bit switch 3/8
      15 : showSwitchBooleanList(typeindex,unitindex,optindex,3);                  // bit switch 4/8
      16 : showSwitchBooleanList(typeindex,unitindex,optindex,4);                  // bit switch 5/8
      17 : showSwitchBooleanList(typeindex,unitindex,optindex,5);                  // bit switch 6/8
      18 : showSwitchBooleanList(typeindex,unitindex,optindex,6);                  // bit switch 7/8
      19 : showSwitchBooleanList(typeindex,unitindex,optindex,7);                  // bit switch 8/8
      20 : showValuesList(typeindex,unitindex,optindex,percentages);               // percentages
      21 : showValuesList(typeindex,unitindex,optindex,music);                     // music
      22 : showinputChar(typeindex,unitindex,optindex);                            // character
      23 : showValuesList(typeindex,unitindex,optindex,palaceSpecials);            // palace special abilities
      24 : showBasicList(typeindex,unitindex,optindex,true);                       // SHP Graphics
      25 : showValuesList(typeindex,unitindex,optindex,displayModes);              // unit display modes
      26 : showValuesList(typeindex,unitindex,optindex,interruptModes);            // action interrupt modes
      27 : showValuesList(typeindex,unitindex,optindex,sidebarModes);              // sidebar modes
      28 : showValuesList(typeindex,unitindex,optindex,vocsounds);                 // voc sounds
      29 : showBasicList(typeindex,unitindex,optindex,false);                      // parent PAK
      30 : showValuesList(typeindex,unitindex,optindex,fileTypes);                 // file type
      31 : ; {no special show instructions needed}                                 // structure animation
      32 : showValuesList(typeindex,unitindex,optindex,structureGraphics);         // structure graphics set
     end;
   end
  else if edtype=1 then showinputBin(typeindex,unitindex,optindex)
  else if edtype=2 then showinputHex(typeindex,unitindex,optindex)
  else if edtype=3 then showinputInt2(typeindex,unitindex,optindex);
  if level<>4 then
   begin
     if HexDisplay then
     begin
      lev2List[unitindex]:=getDataStr(typeindex,unitindex,refoption[typeindex]);
      hexdisplay_adaptlist2item(unitindex);
     end;
     ClearWorkArea();
     drawLevFrames();
     drawLists();
     drawSelects();
   end;
end;

procedure drawLayout();
begin
   if level=4 then drawLayout4(0)
   else drawLevFrames();
end;

procedure FillWorkArea();
begin
      ClearWorkArea();
      drawLayout();
      drawLists();
      drawSelects();
end;

// =========================================
//              LEVEL 4 CONTROLS
// =========================================

procedure startlev4();
begin
  prevlev:=level;
  level:=4;
  if not HexDisplay then drawLayout()
  else
    begin
      if (lev3list[select[3]+scroll[3]].typeid >=12) and (lev3list[select[3]+scroll[3]].typeid <=19) then
        drawLayout4(1)
      else
        drawLayout4(2);
    end;
end;

procedure startlev4bin();
begin
  prevlev:=level;
  level:=4;
  drawLayout4(1);
end;

procedure startlev4hex();
begin
  prevlev:=level;
  level:=4;
  drawLayout4(2);
end;

procedure startlev4dec();
begin
  prevlev:=level;
  level:=4;
  drawLayout4(3);
end;

procedure exitlev4();
begin
  select[4]:=0;
  scroll[4]:=0;
  level:=prevlev;
  if binEd then
  begin
    if HexDisplay then
    begin
      lev2List[select[2]+scroll[2]]:=getDataStr(select[1]+scroll[1],select[2]+scroll[2],refoption[select[1]+scroll[1]]);
      hexdisplay_adaptlist2item(select[2]+scroll[2]);
    end;
    binEd:=false;
  end;
  FillWorkArea();
end;

// =========================================
//              OUTPUT PROCEDURES
// =========================================

procedure savePrerequisites(typeindex,unitindex,optindex:integer);
var
 o:boollist;
 listpos:integer;
begin
  if keyread=keymap.SPACE then
   begin
     o:=readPrerequisites(typeindex,unitindex,optindex);
     listpos:=select[4]+scroll[4];
     o[listpos]:=(not o[listpos]);
     writePrerequisites(o,typeindex,unitindex,optindex);
     drawLev4();
   end
  else if keyread=keymap.ENTER then exitlev4();
end;

procedure saveBasicList(typeindex,unitindex,optindex:integer;hasblank:boolean);
var
  value:integer;
begin
  value:=select[4]+scroll[4];
  if hasblank then value:=value-1;
  writeBytesInt(getAddress(typeindex,unitindex,optindex),value,getDataLen(typeindex,optindex));
  exitlev4();
end;

procedure saveValuesList(typeindex,unitindex,optindex:integer; vallist:array of values);
var
  value:integer;
begin
  value:=vallist[(select[4]+scroll[4])].val;
  writeBytesInt(getAddress(typeindex,unitindex,optindex),value,getDataLen(typeindex,optindex));
  exitlev4();
end;

procedure saveBitSwitchList(typeindex,unitindex,optindex,bitindex:integer);
var
  value:integer;
begin
  value:=select[4]+scroll[4];
  writeSwitchBoolean((value=1),typeindex,unitindex,optindex,bitindex);
  exitlev4();
end;

procedure inputLev4();
var
    typeindex,unitindex,optindex:integer;
begin
  typeindex:=select[1]+scroll[1];
  unitindex:=select[2]+scroll[2];
  optindex:=select[3]+scroll[3];
  if binEd then savePrerequisites(typeindex,unitindex,optindex)
  else
  // DATA TYPE LIST - Determines which procedure to call to save each data type
  //                  when the list is opened
   case lev3list[select[3]+scroll[3]].typeid of
       0 : saveValuesList(typeindex,unitindex,optindex,booleans);                  // 2-byte boolean
       1 : ;                                                                       // signed byte
       2 : ;                                                                       // 2-byte
       3 : ;                                                                       // 4-byte (REF)
       4 : savePrerequisites(typeindex,unitindex,optindex);                        // owners
       5 : saveBasicList(typeindex,unitindex,optindex,true);                       // command
       6 : saveBasicList(typeindex,unitindex,optindex,false);                      // movement type
       7 : saveBasicList(typeindex,unitindex,optindex,true);                       // weapon type
       8 : saveValuesList(typeindex,unitindex,optindex,foundations);               // foundation
       9 : saveValuesList(typeindex,unitindex,optindex,decayFactors);              // decay factor
      10 : savePrerequisites(typeindex,unitindex,optindex);                        // prerequisites
      11 : saveValuesList(typeindex,unitindex,optindex,sounds);                    // sounds
      12 : saveBitSwitchList(typeindex,unitindex,optindex,0);                      // bit switch 1/8
      13 : saveBitSwitchList(typeindex,unitindex,optindex,1);                      // bit switch 2/8
      14 : saveBitSwitchList(typeindex,unitindex,optindex,2);                      // bit switch 3/8
      15 : saveBitSwitchList(typeindex,unitindex,optindex,3);                      // bit switch 4/8
      16 : saveBitSwitchList(typeindex,unitindex,optindex,4);                      // bit switch 5/8
      17 : saveBitSwitchList(typeindex,unitindex,optindex,5);                      // bit switch 6/8
      18 : saveBitSwitchList(typeindex,unitindex,optindex,6);                      // bit switch 7/8
      19 : saveBitSwitchList(typeindex,unitindex,optindex,7);                      // bit switch 8/8
      20 : saveValuesList(typeindex,unitindex,optindex,percentages);               // percentages
      21 : saveValuesList(typeindex,unitindex,optindex,music);                     // music
      22 : ;                                                                       // character
      23 : saveValuesList(typeindex,unitindex,optindex,palaceSpecials);            // palace special abilities
      24 : saveBasicList(typeindex,unitindex,optindex,true);                       // SHP Graphics
      25 : saveValuesList(typeindex,unitindex,optindex,displayModes);              // unit display modes
      26 : saveValuesList(typeindex,unitindex,optindex,interruptModes);            // action interrupt modes
      27 : saveValuesList(typeindex,unitindex,optindex,SidebarModes);              // sidebar modes
      28 : saveValuesList(typeindex,unitindex,optindex,vocsounds);                 // voc sounds
      29 : saveBasicList(typeindex,unitindex,optindex,false);                      // parent PAK
      30 : saveValuesList(typeindex,unitindex,optindex,fileTypes);                 // file type
      31 : ; {Add function to open & edit current level 4 list item?}              // structure animation
      32 : saveValuesList(typeindex,unitindex,optindex, structureGraphics);        // structure graphics set
   end;
end;

// =========================================
//              DATA DUMP FUNCTIONS
// =========================================

procedure dumpToIni(filename:String);
Var
    iniFile : Text;
    i, endi, typeindex, unitindex, optindex:integer;
    HexDisplayOrig:boolean;
Begin
  HexDisplayOrig:=HexDisplay;
  HexDisplay:=false;
  Assign(iniFile,filename); {assign a text file}
  Rewrite(iniFile); {open the file as empty file for writing}
  writeln(iniFile,'; Rules dump for version "'+ dunever[gamever] + '" ('+ dunevername[gamever] +')');
  writeln(iniFile,';');
  endi:=7;
  while (endi >= 1) and (duneverinfo[gamever][endi]='') do
   endi:=endi-1;

  for i:=1 to endi do
  begin
    if duneverinfo[gamever][i]<>'' then
       writeln(iniFile,'; ' + duneverinfo[gamever][i]);
  end;
  writeln(iniFile,';');
  for typeindex:=low(mainlist) to high(mainlist) do
  begin
    writeln(iniFile,'');
    writeln(iniFile,'');
    writeln(iniFile,'; '+mainlist[typeindex]);
    for unitindex:=0 to typeListLen[typeindex][gamever]-1 do
    begin
      writeln(iniFile,'');
      writeln(iniFile,'['+ BasicType(unitindex,typeindex) +']');
      optindex:=0;
      while TypeOptsList[typeindex][optindex].typeid<>-1 do
      begin
        writeln(iniFile,TypeOptsList[typeindex][optindex].text + ' = ' + TrimRight(getDataStr(typeindex, unitindex, optindex, false)));
        optindex:=optindex+1;
      end;
    end;
  end;
  Close(iniFile);
  HexDisplay:=HexDisplayOrig;
End;

// =========================================
//              HELP & INFO SCREENS
// =========================================

procedure greyframes();
begin
  prevlev:=level;
  level:=4;
  drawLevFrame(prevlev,true);
  drawList(prevlev);
  drawSelect(prevlev);
  level:=prevlev;
end;

procedure egotrip();
var
   x,y,width,height,i:integer;
begin
  greyframes();
  x:=15;
  y:=4;
  width:=52;
  height:=19;
  drawFrame(x,y,width,height,-1,true,true);
  x:=x+2;
  gotoxy(x,y); write('[INFO]');
  y:=y+1; gotoxy(x,y); write(editorname + ' ' + editorversion);
  gotoxy(x+31,y); write('Powered by Pascal');
  y:=y+1; gotoxy(x,y); for i:=1 to length(editorname+editorversion)+1 do write(char(framechar[1][5]));
//           length of line: '________________________________________________'
  y:=y+1; gotoxy(x,y); write('Created by ' + editorauthor + ' <' + editorauthoremail + '>');
  y:=y+1; gotoxy(x,y); write('Project started on February 27, 2008.');
  y:=y+1; gotoxy(x,y); write('Current version: ' + editorversiondate + '.');
  y:=y+1; 
  y:=y+1; gotoxy(x,y); write('Originally requested by MrFlibble, to help him');
  y:=y+1; gotoxy(x,y); write('in his efforts to create the "Super Dune II');
  y:=y+1; gotoxy(x,y); write('Second Edition" mod.');
  y:=y+1; 
  y:=y+1; gotoxy(x,y); write('Many thanks to MrFlibble for providing me with');
  y:=y+1; gotoxy(x,y); write('a description of the data structures in Dune II,');
  y:=y+1; gotoxy(x,y); write('and to Segra for his research into the exe file');
  y:=y+1; gotoxy(x,y); write('which has helped to identify lots of options.');
  y:=y+1; 
  y:=y+1; gotoxy(x,y); write('Layout based on the "C&C structure editor V1.02"');
  y:=y+1; gotoxy(x,y); write('by Wladimir van der Laan.');

  resetCursor();
  cntin();
  FillWorkArea();
end;

procedure help();
var
   x,y,width,height,i:integer;
   help:bigdescr;
begin
  greyframes();
  x:=15;
  y:=4;
  width:=52;
  height:=20;
  if level=3 then   // type-specific help
  begin
   y:=7;
   height:=12;
  end;
  drawFrame(x,y,width,height,-1,true,true);
  x:=x+2;
  gotoxy(x,y); write('[HELP]');
  y:=y+1; gotoxy(x,y); write(editorname + ' ' + editorversion);
  y:=y+1; gotoxy(x,y); for i:=1 to length(editorname+editorversion)+1 do write(char(framechar[1][5]));
  if level=3 then
   // type-specific help
   begin
    help:=GetOptHelp(lev3List[select[3]+scroll[3]].helpid);
    for i:=1 to 7 do
     begin
       y:=y+1;
       gotoxy(x,y);
       write(help[i]);
     end;
   end
  else
   // general program help
   begin
//           allowed length #1: '____________'
//           allowed length #2:    ': ___________________________________'
     y:=y+1; gotoxy(x,y); write('LEFT/RIGHT');
             gotoxy(x+11,y); write(': Navigate between sections');
     y:=y+1; gotoxy(x,y); write('UP/DOWN');
             gotoxy(x+11,y); write(': Navigate through section list');
     y:=y+1; gotoxy(x+14,y);    write('Use PAGEUP, PAGEDOWN, HOME and END');
     y:=y+1; gotoxy(x+14,y);    write('for faster scrolling.');
     y:=y+1; 
     y:=y+1; gotoxy(x,y); write('SPACE/ENTER');
             gotoxy(x+11,y); write(': Modify/confirm selected value');
     y:=y+1; gotoxy(x,y); write('F1/H');
             gotoxy(x+11,y); write(': Shows help on the selected option');
     y:=y+1; gotoxy(x,y); write('F2/B');
             gotoxy(x+11,y); write(': Edit as bare binary value');
     y:=y+1; gotoxy(x,y); write('F3/X');
             gotoxy(x+11,y); write(': Edit as bare hexadecimal value');
     y:=y+1; gotoxy(x,y); write('F4/D');
             gotoxy(x+11,y); write(': Edit as bare decimal value');
     y:=y+1; 
     y:=y+1; gotoxy(x,y); write('F9/V');
             gotoxy(x+11,y); write(': Dune EXE version information');
     y:=y+1; gotoxy(x,y); write('F10/N');
             gotoxy(x+11,y); write(': Dumps all data to an ini-file');
     y:=y+1; gotoxy(x,y); write('F11/R');
             gotoxy(x+11,y); write(': Toggles hexadecimal "Research" mode');
     y:=y+1; gotoxy(x,y); write('F12/I');
             gotoxy(x+11,y); write(': Info screen about the editor');
     y:=y+1; gotoxy(x,y); write('[ESC]');
             gotoxy(x+11,y); write(': Exit the program');
   end;
  resetCursor();
  cntin();
  FillWorkArea();
end;

procedure versioninfo();
var
   x,y,width,height,i:integer;
   help:bigdescr;
begin
  greyframes();
  x:=15;
  y:=7;
  width:=52;
  height:=11;
  drawFrame(x,y,width,height,-1,true,true);
  x:=x+2;
  gotoxy(x,y); write('[GAME VERSION INFO]');
  help:=duneverinfo[gamever];
  y:=y+1; gotoxy(x,y); write(dunevername[gamever]);
  y:=y+1; gotoxy(x,y); for i:=1 to length(dunevername[gamever]) do write(char(framechar[1][5]));
  help:=duneverinfo[gamever];
  for i:=1 to 7 do
   begin
     y:=y+1;
     gotoxy(x,y);
     write(help[i]);
   end;
  resetCursor();
  cntin();
  FillWorkArea();
end;

procedure showDumpToIni();
var
   x,y,width,height:integer;
   rulesfile:String;
begin
  greyframes();
  rulesfile:=ExtractFilePath(gamepathstr) + rulesfileprefix + dunever[gamever] + '.' + rulesfileext;
  x:=10;
  y:=10;
  width:=62;
  height:=7;
  drawFrame(x,y,width,height,-1,true,true);
  x:=x+2;
  gotoxy(x,y); write('[GAME INFO DUMP]');
  y:=y+2; gotoxy(x,y); write('Dumping information to:');
  y:=y+1; gotoxy(x,y);
  if length(rulesfile)>58 then
     write(trimRight(Copy(rulesfile,1,27)) + '...' + TrimLeft(Copy(rulesfile,length(rulesfile)-27,length(rulesfile))))
  else
     write(rulesfile);
  DumpToIni(rulesfile);
  y:=y+1; gotoxy(x,y); write('Done.');
  resetCursor();
  cntin();
  FillWorkArea();
end;


// =========================================
//                NAVIGATION
// =========================================

procedure MoveVertGen(scr,sel:integer);
begin
  if scr<>scroll[level] then drawList();
  if sel<>select[level] then
   if not BinEd then
    begin
      drawSelect(level,sel);
      drawSelect(level,select[level]);
    end
   else
    drawSelectBin();
  if  (scr<>scroll[level]) or (sel<>select[level]) then
   begin
     if level=1 then updateLists();
     if level=2 then drawLev3data();
     if (level=3) and (HexDisplay) then
       begin
         updateLev2Lists();
         drawLev2();
       end;
   end;
end;

procedure MoveHorGen(oldlevel:integer);
begin
  if oldlevel<>level then
   begin
     if not binEd then drawLevFrame(oldlevel);
     drawLevFrame(level);
     if not binEd then drawList(oldlevel);
     drawList(level);
     if not binEd then drawSelect(oldlevel);
     drawSelect(level);
   end;
end;

procedure MoveDown2(lines:integer);
var scr,sel:integer;
begin
  scr:=scroll[level];
  sel:=select[level];
  if not binEd then MoveDown(lines)
  else MoveUp(lines);
  MoveVertGen(scr,sel);
end;

procedure MoveUp2(lines:integer);
var scr,sel:integer;
begin
  scr:=scroll[level];
  sel:=select[level];
  if not binEd then MoveUp(lines)
  else MoveDown(lines);
  MoveVertGen(scr,sel);
end;

procedure MoveRight2();
var oldlevel:integer;
begin
  oldlevel:=level;
  MoveRight();
  MoveHorGen(oldlevel);
end;

procedure MoveLeft2();
var oldlevel:integer;
begin
  oldlevel:=level;
  MoveLeft();
  MoveHorGen(oldlevel);
end;

procedure SwitchHexDisplay();
begin
  HexDisplay:=not HexDisplay;
  updateLev2Lists();
  drawLev2();
  drawLev3data();
end;

procedure input();
begin
  keyread:=ReadKey();
  if (keyread=keymap.ESC) and (level<>4) then keyread:=char(255)
  else if (level=4) and ((keyread=keymap.ESC) or (keyread=keymap.F2) or (keyread='b') or (keyread=keymap.F3) or (keyread='x') or (keyread=keymap.F4) or (keyread='d')) then exitlev4()
  else if ((level=2) or (level=3)) and ((keyread=keymap.ENTER) or (keyread=keymap.SPACE)) then startlev4()
  else if ((level=2) or (level=3)) and ((keyread=keymap.F2) or (keyread='b')) then startlev4bin()
  else if ((level=2) or (level=3)) and ((keyread=keymap.F3) or (keyread='x')) then startlev4hex()
  else if ((level=2) or (level=3)) and ((keyread=keymap.F4) or (keyread='d')) then startlev4dec()
  else if (keyread=keymap.RIGHT) and (level<>4) then MoveRight2()
  else if (keyread=keymap.RIGHT) and (level=4) then MoveDown2(1)
  else if (keyread=keymap.LEFT)  and (level<>4) then MoveLeft2()
  else if (keyread=keymap.LEFT)  and (level=4) then MoveUp2(1)
  else if (keyread=keymap.DOWN)  then MoveDown2(1)
  else if (keyread=keymap.UP)    then MoveUp2(1)
  else if (keyread=keymap.PGDN)  then MoveDown2(maxdisplay[level])
  else if (keyread=keymap.PGUP)  then MoveUp2(maxdisplay[level])
  else if (keyread=keymap.ENDK)  then MoveDown2(listlen[level])
  else if (keyread=keymap.HOME)  then MoveUp2(listlen[level])
  else if ((keyread=keymap.F1)   or (keyread='h')) and (level<>4) then help()
  else if ((keyread=keymap.F9)   or (keyread='v')) and (level<>4) then versioninfo()
  else if ((keyread=keymap.F10)  or (keyread='n')) and (level<>4) then showDumpToIni()
  else if ((keyread=keymap.F11)  or (keyread='r')) and (level<>4) then SwitchHexDisplay()
  else if ((keyread=keymap.F12)  or (keyread='i')) and (level<>4) then egotrip()
  else if (level=4) and ((keyread=keymap.SPACE) or (keyread=keymap.ENTER)) then inputlev4()
  else keyread:=char(0);
end;

// =========================================
//               INITIALIZATION
// =========================================

function GetOptsListLength(list:lev3Lst):integer;
var i: integer;
begin
  GetOptsListLength:=-1;
  for i:=0 to high(list) do
    if list[i].typeid<>-1 then GetOptsListLength:=GetOptsListLength+1
    else break;
end;

procedure SetOptsListLengths();
var i: integer;
begin
  for i:=0 to high(TypeOptsList) do
      optsListlengths[i]:=GetOptsListLength(TypeOptsList[i]);
end;

procedure init();
var i: integer;
begin
  BinEd:=false;
  HexDisplay:=false;
  TextBackground(inactivelevbgcolor);
  TextColor(inactivelevcolor);
  clrScr();
  drawHeaders();
  level:=1;
  SetOptsListLengths();
  for i:=1 to high(listlen) do
  begin
   select[i]:=0;
   scroll[i]:=0;
   listlen[i]:=0;
  end;
  listlen[1]:=high(mainlist);
  listlen[2]:=typeListLen[0][gamever];
  listlen[3]:=optsListlengths[0];
  updateLev2Lists();
  FillWorkArea();
end;

procedure checkver(checkstring:string);
var
 i: integer;
 s: string;
begin
  gamever:=-1;
  i:=0;
  while ((gamever=-1) and (i<=high(verAddress))) do
   begin
     s:=readString(verAddress[i]);
     if (uppercase(s) = uppercase(checkstring)) then gamever:=i;
     i:=i+1;
   end;
end;

procedure initfilename();
var
 filename:string;
 filenamelen:integer;
begin
  gamenamestr:=defnamestr;
  gamepathstr:=ExpandFileName(defnamestr);
  if ParamCount <> 0 then
   begin
     filename:=ExtractFileName(ParamStr(1));
     filenamelen:=length(filename);
     if (filenamelen > 0) then
      begin
        gamepathstr:=ExpandFileName(ParamStr(1));
        gamenamestr:=uppercase(filename);
      end;
   end;
end;

begin
  clrscr();
  gotoxy(1,3);
  initfilename();
  if (openfile(gamepathstr)) then
   begin
     checkver(gamenamestr);
     if (gamever=-1) and (uppercase(defnamestr)<>uppercase(gamenamestr)) then checkver(defnamestr);
     if gamever<>-1 then
      begin
        init();
        keyread:=char(0);
        while (keyread <> char(255)) do
         begin
           input(); // MAIN FUNCTION
         end;
        closeFile();
        NormVideo;
        clrscr();
        drawHeader();
        gotoxy(1,25);
        gotoxy(1,3);
        writeln('Program exited. Have fun!');
      end
     else
      begin
        closeFile();
        NormVideo;
        clrscr();
        drawHeader();
        gotoxy(1,25);
        gotoxy(1,3);
        writeln('ERROR: Cannot identify the Dune 2 version of the file "', gamenamestr,'".');
        cntin(true);
      end;
   end
  else
   begin
     drawHeader();
     gotoxy(1,4);
     cntin(true);
   end;
end.

