/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/

/*
* Based on the Reverse Engineering work of Christophe Fontanel,
* maintainer of the Dungeon Master Encyclopaedia (http://dmweb.free.fr/)
*/

#include "common/file.h"
#include "common/memstream.h"

#include "dungeonman.h"
#include "timeline.h"



namespace DM {

ObjectInfo g237_ObjectInfo[180] = { // @ G0237_as_Graphic559_ObjectInfo
/* { Type, ObjectAspectIndex, ActionSetIndex, AllowedSlots } */
	ObjectInfo(30,  1,  0, 0x0500),   /* COMPASS        Pouch/Chest */
	ObjectInfo(144,  0,  0, 0x0200),   /* COMPASS        Hands */
	ObjectInfo(148, 67,  0, 0x0500),   /* COMPASS        Pouch/Chest */
	ObjectInfo(149, 67,  0, 0x0500),   /* COMPASS        Pouch/Chest */
	ObjectInfo(150, 67,  0, 0x0500),   /* TORCH          Pouch/Chest */
	ObjectInfo(151, 67, 42, 0x0500),   /* TORCH          Pouch/Chest */
	ObjectInfo(152, 67,  0, 0x0500),   /* TORCH          Pouch/Chest */
	ObjectInfo(153, 67,  0, 0x0500),   /* TORCH          Pouch/Chest */
	ObjectInfo(154,  2,  0, 0x0501),   /* WATERSKIN      Mouth/Pouch/Chest */
	ObjectInfo(155,  2,  0, 0x0501),   /* WATER          Mouth/Pouch/Chest */
	ObjectInfo(156,  2,  0, 0x0501),   /* JEWEL SYMAL    Mouth/Pouch/Chest */
	ObjectInfo(157,  2,  0, 0x0501),   /* JEWEL SYMAL    Mouth/Pouch/Chest */
	ObjectInfo(158,  2,  0, 0x0501),   /* ILLUMULET      Mouth/Pouch/Chest */
	ObjectInfo(159,  2,  0, 0x0501),   /* ILLUMULET      Mouth/Pouch/Chest */
	ObjectInfo(160,  2,  0, 0x0501),   /* FLAMITT        Mouth/Pouch/Chest */
	ObjectInfo(161,  2,  0, 0x0501),   /* FLAMITT        Mouth/Pouch/Chest */
	ObjectInfo(162,  2,  0, 0x0501),   /* EYE OF TIME    Mouth/Pouch/Chest */
	ObjectInfo(163,  2,  0, 0x0501),   /* EYE OF TIME    Mouth/Pouch/Chest */
	ObjectInfo(164, 68,  0, 0x0500),   /* STORMRING      Pouch/Chest */
	ObjectInfo(165, 68,  0, 0x0500),   /* STORMRING      Pouch/Chest */
	ObjectInfo(166, 68,  0, 0x0500),   /* STAFF OF CLAWS Pouch/Chest */
	ObjectInfo(167, 68, 42, 0x0500),   /* STAFF OF CLAWS Pouch/Chest */
	ObjectInfo(195, 80,  0, 0x0500),   /* STAFF OF CLAWS Pouch/Chest */
	ObjectInfo(16, 38, 43, 0x0500),   /* BOLT BLADE     Pouch/Chest */
	ObjectInfo(18, 38,  7, 0x0500),   /* BOLT BLADE     Pouch/Chest */
	ObjectInfo(4, 35,  5, 0x0400),   /* FURY           Chest */
	ObjectInfo(14, 37,  6, 0x0400),   /* FURY           Chest */
	ObjectInfo(20, 11,  8, 0x0040),   /* THE FIRESTAFF  Quiver 1 */
	ObjectInfo(23, 12,  9, 0x0040),   /* THE FIRESTAFF  Quiver 1 */
	ObjectInfo(25, 12, 10, 0x0040),   /* THE FIRESTAFF  Quiver 1 */
	ObjectInfo(27, 39, 11, 0x0040),   /* OPEN SCROLL    Quiver 1 */
	ObjectInfo(32, 17, 12, 0x05C0),   /* SCROLL         Quiver 1/Quiver 2/Pouch/Chest */
	ObjectInfo(33, 12, 13, 0x0040),   /* DAGGER         Quiver 1 */
	ObjectInfo(34, 12, 13, 0x0040),   /* FALCHION       Quiver 1 */
	ObjectInfo(35, 12, 14, 0x0040),   /* SWORD          Quiver 1 */
	ObjectInfo(36, 12, 15, 0x0040),   /* RAPIER         Quiver 1 */
	ObjectInfo(37, 12, 15, 0x0040),   /* SABRE          Quiver 1 */
	ObjectInfo(38, 12, 16, 0x0040),   /* SAMURAI SWORD  Quiver 1 */
	ObjectInfo(39, 12, 17, 0x0040),   /* DELTA          Quiver 1 */
	ObjectInfo(40, 42, 18, 0x0040),   /* DIAMOND EDGE   Quiver 1 */
	ObjectInfo(41, 12, 19, 0x0040),   /* VORPAL BLADE   Quiver 1 */
	ObjectInfo(42, 13, 20, 0x0040),   /* THE INQUISITOR Quiver 1 */
	ObjectInfo(43, 13, 21, 0x0040),   /* AXE            Quiver 1 */
	ObjectInfo(44, 21, 22, 0x0040),   /* HARDCLEAVE     Quiver 1 */
	ObjectInfo(45, 21, 22, 0x0040),   /* MACE           Quiver 1 */
	ObjectInfo(46, 33, 23, 0x0440),   /* MACE OF ORDER  Quiver 1/Chest */
	ObjectInfo(47, 43, 24, 0x0040),   /* MORNINGSTAR    Quiver 1 */
	ObjectInfo(48, 44, 24, 0x0040),   /* CLUB           Quiver 1 */
	ObjectInfo(49, 14, 27, 0x0040),   /* STONE CLUB     Quiver 1 */
	ObjectInfo(50, 45, 27, 0x0040),   /* BOW            Quiver 1 */
	ObjectInfo(51, 16, 26, 0x05C0),   /* CROSSBOW       Quiver 1/Quiver 2/Pouch/Chest */
	ObjectInfo(52, 46, 26, 0x05C0),   /* ARROW          Quiver 1/Quiver 2/Pouch/Chest */
	ObjectInfo(53, 11, 27, 0x0440),   /* SLAYER         Quiver 1/Chest */
	ObjectInfo(54, 47, 42, 0x05C0),   /* SLING          Quiver 1/Quiver 2/Pouch/Chest */
	ObjectInfo(55, 48, 40, 0x05C0),   /* ROCK           Quiver 1/Quiver 2/Pouch/Chest */
	ObjectInfo(56, 49, 42, 0x05C0),   /* POISON DART    Quiver 1/Quiver 2/Pouch/Chest */
	ObjectInfo(57, 50,  5, 0x0040),   /* THROWING STAR  Quiver 1 */
	ObjectInfo(58, 11,  5, 0x0040),   /* STICK          Quiver 1 */
	ObjectInfo(59, 31, 28, 0x0540),   /* STAFF          Quiver 1/Pouch/Chest */
	ObjectInfo(60, 31, 29, 0x0540),   /* WAND           Quiver 1/Pouch/Chest */
	ObjectInfo(61, 11, 30, 0x0040),   /* TEOWAND        Quiver 1 */
	ObjectInfo(62, 11, 31, 0x0040),   /* YEW STAFF      Quiver 1 */
	ObjectInfo(63, 11, 32, 0x0040),   /* STAFF OF MANAR Quiver 1 Atari ST Version 1.0 1987-12-08: ObjectAspectIndex = 35 */
	ObjectInfo(64, 51, 33, 0x0040),   /* SNAKE STAFF    Quiver 1 */
	ObjectInfo(65, 32,  5, 0x0440),   /* THE CONDUIT    Quiver 1/Chest */
	ObjectInfo(66, 30, 35, 0x0040),   /* DRAGON SPIT    Quiver 1 */
	ObjectInfo(135, 65, 36, 0x0440),   /* SCEPTRE OF LYF Quiver 1/Chest */
	ObjectInfo(143, 45, 27, 0x0040),   /* ROBE           Quiver 1 */
	ObjectInfo(28, 82,  1, 0x0040),   /* FINE ROBE      Quiver 1 */
	ObjectInfo(80, 23,  0, 0x040C),   /* KIRTLE         Neck/Torso/Chest */
	ObjectInfo(81, 23,  0, 0x040C),   /* SILK SHIRT     Neck/Torso/Chest */
	ObjectInfo(82, 23,  0, 0x0410),   /* ELVEN DOUBLET  Legs/Chest */
	ObjectInfo(112, 55,  0, 0x0420),   /* LEATHER JERKIN Feet/Chest */
	ObjectInfo(114,  8,  0, 0x0420),   /* TUNIC          Feet/Chest */
	ObjectInfo(67, 24,  0, 0x0408),   /* GHI            Torso/Chest */
	ObjectInfo(83, 24,  0, 0x0410),   /* MAIL AKETON    Legs/Chest */
	ObjectInfo(68, 24,  0, 0x0408),   /* MITHRAL AKETON Torso/Chest */
	ObjectInfo(84, 24,  0, 0x0410),   /* TORSO PLATE    Legs/Chest */
	ObjectInfo(69, 69,  0, 0x0408),   /* PLATE OF LYTE  Torso/Chest */
	ObjectInfo(70, 24,  0, 0x0408),   /* PLATE OF DARC  Torso/Chest */
	ObjectInfo(85, 24,  0, 0x0410),   /* CAPE           Legs/Chest */
	ObjectInfo(86, 69,  0, 0x0410),   /* CLOAK OF NIGHT Legs/Chest */
	ObjectInfo(71,  7,  0, 0x0408),   /* BARBARIAN HIDE Torso/Chest */
	ObjectInfo(87,  7,  0, 0x0410),   /* ROBE           Legs/Chest */
	ObjectInfo(119, 57,  0, 0x0420),   /* FINE ROBE      Feet/Chest */
	ObjectInfo(72, 23,  0, 0x0408),   /* TABARD         Torso/Chest */
	ObjectInfo(88, 23,  0, 0x0410),   /* GUNNA          Legs/Chest */
	ObjectInfo(113, 29,  0, 0x0420),   /* ELVEN HUKE     Feet/Chest */
	ObjectInfo(89, 69,  0, 0x0410),   /* LEATHER PANTS  Legs/Chest */
	ObjectInfo(73, 69,  0, 0x0408),   /* BLUE PANTS     Torso/Chest */
	ObjectInfo(74, 24,  0, 0x0408),   /* GHI TROUSERS   Torso/Chest */
	ObjectInfo(90, 24,  0, 0x0410),   /* LEG MAIL       Legs/Chest */
	ObjectInfo(103, 53,  0, 0x0402),   /* MITHRAL MAIL   Head/Chest */
	ObjectInfo(104, 53,  0, 0x0402),   /* LEG PLATE      Head/Chest */
	ObjectInfo(96,  9,  0, 0x0402),   /* POLEYN OF LYTE Head/Chest */
	ObjectInfo(97,  9,  0, 0x0402),   /* POLEYN OF DARC Head/Chest */
	ObjectInfo(98,  9,  0, 0x0402),   /* BEZERKER HELM  Head/Chest */
	ObjectInfo(105, 54, 41, 0x0400),   /* HELMET         Chest */
	ObjectInfo(106, 54, 41, 0x0200),   /* BASINET        Hands */
	ObjectInfo(108, 10, 41, 0x0200),   /* CASQUE 'N COIF Hands */
	ObjectInfo(107, 54, 41, 0x0200),   /* ARMET          Hands */
	ObjectInfo(75, 19,  0, 0x0408),   /* HELM OF LYTE   Torso/Chest */
	ObjectInfo(91, 19,  0, 0x0410),   /* HELM OF DARC   Legs/Chest */
	ObjectInfo(76, 19,  0, 0x0408),   /* CALISTA        Torso/Chest */
	ObjectInfo(92, 19,  0, 0x0410),   /* CROWN OF NERRA Legs/Chest */
	ObjectInfo(99,  9,  0, 0x0402),   /* BUCKLER        Head/Chest */
	ObjectInfo(115, 19,  0, 0x0420),   /* HIDE SHIELD    Feet/Chest */
	ObjectInfo(100, 52,  0, 0x0402),   /* SMALL SHIELD   Head/Chest */
	ObjectInfo(77, 20,  0, 0x0008),   /* WOODEN SHIELD  Torso */
	ObjectInfo(93, 22,  0, 0x0010),   /* LARGE SHIELD   Legs */
	ObjectInfo(116, 56,  0, 0x0420),   /* SHIELD OF LYTE Feet/Chest */
	ObjectInfo(109, 10, 41, 0x0200),   /* SHIELD OF DARC Hands */
	ObjectInfo(101, 52,  0, 0x0402),   /* SANDALS        Head/Chest */
	ObjectInfo(78, 20,  0, 0x0008),   /* SUEDE BOOTS    Torso */
	ObjectInfo(94, 22,  0, 0x0010),   /* LEATHER BOOTS  Legs */
	ObjectInfo(117, 56,  0, 0x0420),   /* HOSEN          Feet/Chest */
	ObjectInfo(110, 10, 41, 0x0200),   /* FOOT PLATE     Hands */
	ObjectInfo(102, 52,  0, 0x0402),   /* GREAVE OF LYTE Head/Chest */
	ObjectInfo(79, 20,  0, 0x0008),   /* GREAVE OF DARC Torso */
	ObjectInfo(95, 22,  0, 0x0010),   /* ELVEN BOOTS    Legs */
	ObjectInfo(118, 56,  0, 0x0420),   /* GEM OF AGES    Feet/Chest */
	ObjectInfo(111, 10, 41, 0x0200),   /* EKKHARD CROSS  Hands */
	ObjectInfo(140, 52,  0, 0x0402),   /* MOONSTONE      Head/Chest */
	ObjectInfo(141, 19,  0, 0x0408),   /* THE HELLION    Torso/Chest */
	ObjectInfo(142, 22,  0, 0x0010),   /* PENDANT FERAL  Legs */
	ObjectInfo(194, 81,  0, 0x0420),   /* COPPER COIN    Feet/Chest */
	ObjectInfo(196, 84,  0, 0x0408),   /* SILVER COIN    Torso/Chest */
	ObjectInfo(0, 34,  0, 0x0500),   /* GOLD COIN      Pouch/Chest */
	ObjectInfo(8,  6,  0, 0x0501),   /* BOULDER        Mouth/Pouch/Chest */
	ObjectInfo(10, 15,  0, 0x0504),   /* BLUE GEM       Neck/Pouch/Chest */
	ObjectInfo(12, 15,  0, 0x0504),   /* ORANGE GEM     Neck/Pouch/Chest */
	ObjectInfo(146, 40,  0, 0x0500),   /* GREEN GEM      Pouch/Chest */
	ObjectInfo(147, 41,  0, 0x0400),   /* MAGICAL BOX    Chest */
	ObjectInfo(125,  4, 37, 0x0500),   /* MAGICAL BOX    Pouch/Chest */
	ObjectInfo(126, 83, 37, 0x0500),   /* MIRROR OF DAWN Pouch/Chest */
	ObjectInfo(127,  4, 37, 0x0500),   /* HORN OF FEAR   Pouch/Chest */
	ObjectInfo(176, 18,  0, 0x0500),   /* ROPE           Pouch/Chest */
	ObjectInfo(177, 18,  0, 0x0500),   /* RABBIT'S FOOT  Pouch/Chest */
	ObjectInfo(178, 18,  0, 0x0500),   /* CORBAMITE      Pouch/Chest */
	ObjectInfo(179, 18,  0, 0x0500),   /* CHOKER         Pouch/Chest */
	ObjectInfo(180, 18,  0, 0x0500),   /* DEXHELM        Pouch/Chest */
	ObjectInfo(181, 18,  0, 0x0500),   /* FLAMEBAIN      Pouch/Chest */
	ObjectInfo(182, 18,  0, 0x0500),   /* POWERTOWERS    Pouch/Chest */
	ObjectInfo(183, 18,  0, 0x0500),   /* SPEEDBOW       Pouch/Chest */
	ObjectInfo(184, 62,  0, 0x0500),   /* CHEST          Pouch/Chest */
	ObjectInfo(185, 62,  0, 0x0500),   /* OPEN CHEST     Pouch/Chest */
	ObjectInfo(186, 62,  0, 0x0500),   /* ASHES          Pouch/Chest */
	ObjectInfo(187, 62,  0, 0x0500),   /* BONES          Pouch/Chest */
	ObjectInfo(188, 62,  0, 0x0500),   /* MON POTION     Pouch/Chest */
	ObjectInfo(189, 62,  0, 0x0500),   /* UM POTION      Pouch/Chest */
	ObjectInfo(190, 62,  0, 0x0500),   /* DES POTION     Pouch/Chest */
	ObjectInfo(191, 62,  0, 0x0500),   /* VEN POTION     Pouch/Chest */
	ObjectInfo(128, 76,  0, 0x0200),   /* SAR POTION     Hands */
	ObjectInfo(129,  3,  0, 0x0500),   /* ZO POTION      Pouch/Chest */
	ObjectInfo(130, 60,  0, 0x0500),   /* ROS POTION     Pouch/Chest */
	ObjectInfo(131, 61,  0, 0x0500),   /* KU POTION      Pouch/Chest */
	ObjectInfo(168, 27,  0, 0x0501),   /* DANE POTION    Mouth/Pouch/Chest */
	ObjectInfo(169, 28,  0, 0x0501),   /* NETA POTION    Mouth/Pouch/Chest */
	ObjectInfo(170, 25,  0, 0x0501),   /* BRO POTION     Mouth/Pouch/Chest */
	ObjectInfo(171, 26,  0, 0x0501),   /* MA POTION      Mouth/Pouch/Chest */
	ObjectInfo(172, 71,  0, 0x0401),   /* YA POTION      Mouth/Chest */
	ObjectInfo(173, 70,  0, 0x0401),   /* EE POTION      Mouth/Chest */
	ObjectInfo(174,  5,  0, 0x0501),   /* VI POTION      Mouth/Pouch/Chest */
	ObjectInfo(175, 66,  0, 0x0501),   /* WATER FLASK    Mouth/Pouch/Chest */
	ObjectInfo(120, 15,  0, 0x0504),   /* KATH BOMB      Neck/Pouch/Chest */
	ObjectInfo(121, 15,  0, 0x0504),   /* PEW BOMB       Neck/Pouch/Chest */
	ObjectInfo(122, 58,  0, 0x0504),   /* RA BOMB        Neck/Pouch/Chest */
	ObjectInfo(123, 59,  0, 0x0504),   /* FUL BOMB       Neck/Pouch/Chest */
	ObjectInfo(124, 59,  0, 0x0504),   /* APPLE          Neck/Pouch/Chest */
	ObjectInfo(132, 79, 38, 0x0500),   /* CORN           Pouch/Chest */
	ObjectInfo(133, 63, 38, 0x0500),   /* BREAD          Pouch/Chest */
	ObjectInfo(134, 64,  0, 0x0500),   /* CHEESE         Pouch/Chest */
	ObjectInfo(136, 72, 39, 0x0400),   /* SCREAMER SLICE Chest */
	ObjectInfo(137, 73,  0, 0x0500),   /* WORM ROUND     Pouch/Chest */
	ObjectInfo(138, 74,  0, 0x0500),   /* DRUMSTICK      Pouch/Chest */
	ObjectInfo(139, 75,  0, 0x0504),   /* DRAGON STEAK   Neck/Pouch/Chest */
	ObjectInfo(192, 77,  0, 0x0500),   /* IRON KEY       Pouch/Chest */
	ObjectInfo(193, 78,  0, 0x0500),   /* KEY OF B       Pouch/Chest */
	ObjectInfo(197, 74,  0, 0x0000),   /* SOLID KEY */
	ObjectInfo(198, 41,  0, 0x0400)}; /* SQUARE KEY     Chest */

ArmourInfo g239_ArmourInfo[58] = { // G0239_as_Graphic559_ArmourInfo
/* { Weight, Defense, Attributes, Unreferenced } */
	ArmourInfo(3,   5, 0x01),   /* CAPE */
	ArmourInfo(4,  10, 0x01),   /* CLOAK OF NIGHT */
	ArmourInfo(3,   4, 0x01),   /* BARBARIAN HIDE */
	ArmourInfo(6,   5, 0x02),   /* SANDALS */
	ArmourInfo(16,  25, 0x04),   /* LEATHER BOOTS */
	ArmourInfo(4,   5, 0x00),   /* ROBE */
	ArmourInfo(4,   5, 0x00),   /* ROBE */
	ArmourInfo(3,   7, 0x01),   /* FINE ROBE */
	ArmourInfo(3,   7, 0x01),   /* FINE ROBE */
	ArmourInfo(4,   6, 0x01),   /* KIRTLE */
	ArmourInfo(2,   4, 0x00),   /* SILK SHIRT */
	ArmourInfo(4,   5, 0x01),   /* TABARD */
	ArmourInfo(5,   7, 0x01),   /* GUNNA */
	ArmourInfo(3,  11, 0x02),   /* ELVEN DOUBLET */
	ArmourInfo(3,  13, 0x02),   /* ELVEN HUKE */
	ArmourInfo(4,  13, 0x02),   /* ELVEN BOOTS */
	ArmourInfo(6,  17, 0x03),   /* LEATHER JERKIN */
	ArmourInfo(8,  20, 0x03),   /* LEATHER PANTS */
	ArmourInfo(14,  20, 0x03),   /* SUEDE BOOTS */
	ArmourInfo(6,  12, 0x02),   /* BLUE PANTS */
	ArmourInfo(5,   9, 0x01),   /* TUNIC */
	ArmourInfo(5,   8, 0x01),   /* GHI */
	ArmourInfo(5,   9, 0x01),   /* GHI TROUSERS */
	ArmourInfo(4,   1, 0x04),   /* CALISTA */
	ArmourInfo(6,   5, 0x04),   /* CROWN OF NERRA */
	ArmourInfo(11,  12, 0x05),   /* BEZERKER HELM */
	ArmourInfo(14,  17, 0x05),   /* HELMET */
	ArmourInfo(15,  20, 0x05),   /* BASINET */
	ArmourInfo(11,  22, 0x85),   /* BUCKLER */
	ArmourInfo(10,  16, 0x82),   /* HIDE SHIELD */
	ArmourInfo(14,  20, 0x83),   /* WOODEN SHIELD */
	ArmourInfo(21,  35, 0x84),   /* SMALL SHIELD */
	ArmourInfo(65,  35, 0x05),   /* MAIL AKETON */
	ArmourInfo(53,  35, 0x05),   /* LEG MAIL */
	ArmourInfo(52,  70, 0x07),   /* MITHRAL AKETON */
	ArmourInfo(41,  55, 0x07),   /* MITHRAL MAIL */
	ArmourInfo(16,  25, 0x06),   /* CASQUE 'N COIF */
	ArmourInfo(16,  30, 0x06),   /* HOSEN */
	ArmourInfo(19,  40, 0x07),   /* ARMET */
	ArmourInfo(120,  65, 0x04),   /* TORSO PLATE */
	ArmourInfo(80,  56, 0x04),   /* LEG PLATE */
	ArmourInfo(28,  37, 0x05),   /* FOOT PLATE */
	ArmourInfo(34,  56, 0x84),   /* LARGE SHIELD */
	ArmourInfo(17,  62, 0x05),   /* HELM OF LYTE */
	ArmourInfo(108, 125, 0x04),   /* PLATE OF LYTE */
	ArmourInfo(72,  90, 0x04),   /* POLEYN OF LYTE */
	ArmourInfo(24,  50, 0x05),   /* GREAVE OF LYTE */
	ArmourInfo(30,  85, 0x84),   /* SHIELD OF LYTE */
	ArmourInfo(35,  76, 0x04),   /* HELM OF DARC */
	ArmourInfo(141, 160, 0x04),   /* PLATE OF DARC */
	ArmourInfo(90, 101, 0x04),   /* POLEYN OF DARC */
	ArmourInfo(31,  60, 0x05),   /* GREAVE OF DARC */
	ArmourInfo(40, 100, 0x84),   /* SHIELD OF DARC */
	ArmourInfo(14,  54, 0x06),   /* DEXHELM */
	ArmourInfo(57,  60, 0x07),   /* FLAMEBAIN */
	ArmourInfo(81,  88, 0x04),   /* POWERTOWERS */
	ArmourInfo(3,  16, 0x02),   /* BOOTS OF SPEED */
	ArmourInfo(2,   3, 0x03)}; /* HALTER */

WeaponInfo g238_WeaponInfo[46] = { // @ G0238_as_Graphic559_WeaponInfo
							   /* { Weight, Class, Strength, KineticEnergy, Attributes } */
	WeaponInfo(1, 130,   2,   0, 0x2000),   /* EYE OF TIME */
	WeaponInfo(1, 131,   2,   0, 0x2000),   /* STORMRING */
	WeaponInfo(11, 0,   8,   2, 0x2000),   /* TORCH */
	WeaponInfo(12, 112,  10,  80, 0x2028),   /* FLAMITT */
	WeaponInfo(9, 129,  16,   7, 0x2000),   /* STAFF OF CLAWS */
	WeaponInfo(30, 113,  49, 110, 0x0942),   /* BOLT BLADE */
	WeaponInfo(47, 0,  55,  20, 0x0900),   /* FURY */
	WeaponInfo(24, 255,  25,  10, 0x20FF),   /* THE FIRESTAFF */
	WeaponInfo(5, 2,  10,  19, 0x0200),   /* DAGGER */
	WeaponInfo(33, 0,  30,   8, 0x0900),   /* FALCHION */
	WeaponInfo(32, 0,  34,  10, 0x0900),   /* SWORD */
	WeaponInfo(26, 0,  38,  10, 0x0900),   /* RAPIER */
	WeaponInfo(35, 0,  42,  11, 0x0900),   /* SABRE */
	WeaponInfo(36, 0,  46,  12, 0x0900),   /* SAMURAI SWORD */
	WeaponInfo(33, 0,  50,  14, 0x0900),   /* DELTA */
	WeaponInfo(37, 0,  62,  14, 0x0900),   /* DIAMOND EDGE */
	WeaponInfo(30, 0,  48,  13, 0x0000),   /* VORPAL BLADE */
	WeaponInfo(39, 0,  58,  15, 0x0900),   /* THE INQUISITOR */
	WeaponInfo(43, 2,  49,  33, 0x0300),   /* AXE */
	WeaponInfo(65, 2,  70,  44, 0x0300),   /* HARDCLEAVE */
	WeaponInfo(31, 0,  32,  10, 0x2000),   /* MACE */
	WeaponInfo(41, 0,  42,  13, 0x2000),   /* MACE OF ORDER */
	WeaponInfo(50, 0,  60,  15, 0x2000),   /* MORNINGSTAR */
	WeaponInfo(36, 0,  19,  10, 0x2700),   /* CLUB */
	WeaponInfo(110, 0,  44,  22, 0x2600),   /* STONE CLUB */
	WeaponInfo(10, 20,   1,  50, 0x2032),   /* BOW */
	WeaponInfo(28, 30,   1, 180, 0x2078),   /* CROSSBOW */
	WeaponInfo(2, 10,   2,  10, 0x0100),   /* ARROW */
	WeaponInfo(2, 10,   2,  28, 0x0500),   /* SLAYER */
	WeaponInfo(19, 39,   5,  20, 0x2032),   /* SLING */
	WeaponInfo(10, 11,   6,  18, 0x2000),   /* ROCK */
	WeaponInfo(3, 12,   7,  23, 0x0800),   /* POISON DART */
	WeaponInfo(1, 1,   3,  19, 0x0A00),   /* THROWING STAR */
	WeaponInfo(8, 0,   4,   4, 0x2000),   /* STICK */
	WeaponInfo(26, 129,  12,   4, 0x2000),   /* STAFF */
	WeaponInfo(1, 130,   0,   0, 0x2000),   /* WAND */
	WeaponInfo(2, 140,   1,  20, 0x2000),   /* TEOWAND */
	WeaponInfo(35, 128,  18,   6, 0x2000),   /* YEW STAFF */
	WeaponInfo(29, 159,   0,   4, 0x2000),   /* STAFF OF MANAR */
	WeaponInfo(21, 131,   0,   3, 0x2000),   /* SNAKE STAFF */
	WeaponInfo(33, 136,   0,   7, 0x2000),   /* THE CONDUIT */
	WeaponInfo(8, 132,   3,   1, 0x2000),   /* DRAGON SPIT */
	WeaponInfo(18, 131,   9,   4, 0x2000),   /* SCEPTRE OF LYF */
	WeaponInfo(8, 192,   1,   1, 0x2000),   /* HORN OF FEAR */
	WeaponInfo(30, 26,   1, 220, 0x207D),   /* SPEEDBOW */
	WeaponInfo(36, 255, 100,  50, 0x20FF)}; /* THE FIRESTAFF */

CreatureInfo g243_CreatureInfo[k27_CreatureTypeCount] = { // @ G0243_as_Graphic559_CreatureInfo
												   /* { CreatureAspectIndex, AttackSoundOrdinal, Attributes, GraphicInfo,
												   MovementTicks, AttackTicks, Defense, BaseHealth, Attack, PoisonAttack,
												   Dexterity, Ranges, Properties, Resistances, AnimationTicks, WoundProbabilities, AttackType } */
	{0,  4, 0x0482, 0x623D,   8, 20,  55, 150, 150, 240,  55, 0x1153, 0x299B, 0x0876, 0x0254, 0xFD40, 4},
	{1,  0, 0x0480, 0xA625,  15, 32,  20, 110,  80,  15,  20, 0x3132, 0x33A9, 0x0E42, 0x0384, 0xFC41, 3},
	{2,  6, 0x0510, 0x6198,   3,  5,  50,  10,  10,   0, 110, 0x1376, 0x710A, 0x0235, 0x0222, 0xFD20, 0},
	{3,  0, 0x04B4, 0xB225,  10, 21,  30,  40,  58,   0,  80, 0x320A, 0x96AA, 0x0B3C, 0x0113, 0xF910, 5},
	{4,  1, 0x0701, 0xA3B8,   9,  8,  45, 101,  90,   0,  65, 0x1554, 0x58FF, 0x0A34, 0x0143, 0xFE93, 4},
	{5,  0, 0x0581, 0x539D,  20, 18, 100,  60,  30,   0,  30, 0x1232, 0x4338, 0x0583, 0x0265, 0xFFD6, 3},
	{6,  3, 0x070C, 0x0020, 120, 10,   5, 165,   5,   0,   5, 0x1111, 0x10F1, 0x0764, 0x02F2, 0xFC84, 6},
	{7,  7, 0x0300, 0x0220, 185, 15, 170,  50,  40,   5,  10, 0x1463, 0x25C4, 0x06E3, 0x01F4, 0xFD93, 4}, /* Atari ST: AttackSoundOrdinal = 0 */
	{8,  2, 0x1864, 0x5225,  11, 16,  15,  30,  55,   0,  80, 0x1423, 0x4664, 0x0FC8, 0x0116, 0xFB30, 6},
	{9, 10, 0x0282, 0x71B8,  21, 14, 240, 120, 219,   0,  35, 0x1023, 0x3BFF, 0x0FF7, 0x04F3, 0xF920, 3}, /* Atari ST: AttackSoundOrdinal = 7 */
	{10,  2, 0x1480, 0x11B8,  17, 12,  25,  33,  20,   0,  40, 0x1224, 0x5497, 0x0F15, 0x0483, 0xFB20, 3},
	{11,  0, 0x18C6, 0x0225, 255,  8,  45,  80, 105,   0,  60, 0x1314, 0x55A5, 0x0FF9, 0x0114, 0xFD95, 1},
	{12, 11, 0x1280, 0x6038,   7,  7,  22,  20,  22,   0,  80, 0x1013, 0x6596, 0x0F63, 0x0132, 0xFA30, 4}, /* Atari ST: AttackSoundOrdinal = 8 */
	{13,  9, 0x14A2, 0xB23D,   5, 10,  42,  39,  90, 100,  88, 0x1343, 0x5734, 0x0638, 0x0112, 0xFA30, 4}, /* Atari ST: AttackSoundOrdinal = 0 */
	{14,  0, 0x05B8, 0x1638,  10, 20,  47,  44,  75,   0,  90, 0x4335, 0xD952, 0x035B, 0x0664, 0xFD60, 5},
	{15,  5, 0x0381, 0x523D,  18, 19,  72,  70,  45,  35,  35, 0x1AA1, 0x15AB, 0x0B93, 0x0253, 0xFFC5, 4},
	{16, 10, 0x0680, 0xA038,  13,  8,  28,  20,  25,   0,  41, 0x1343, 0x2148, 0x0321, 0x0332, 0xFC30, 3}, /* Atari ST: AttackSoundOrdinal = 7 */
	{17,  0, 0x04A0, 0xF23D,   1, 16, 180,   8,  28,  20, 150, 0x1432, 0x19FD, 0x0004, 0x0112, 0xF710, 4},
	{18, 11, 0x0280, 0xA3BD,  14,  6, 140,  60, 105,   0,  70, 0x1005, 0x7AFF, 0x0FFA, 0x0143, 0xFA30, 4}, /* Atari ST: AttackSoundOrdinal = 8 */
	{19,  0, 0x0060, 0xE23D,   5, 18,  15,  33,  61,   0,  65, 0x3258, 0xAC77, 0x0F56, 0x0117, 0xFC40, 5},
	{20,  8, 0x10DE, 0x0225,  25, 25,  75, 144,  66,   0,  50, 0x1381, 0x7679, 0x0EA7, 0x0345, 0xFD93, 3}, /* Atari ST: AttackSoundOrdinal = 0 */
	{21,  3, 0x0082, 0xA3BD,   7, 15,  33,  77, 130,   0,  60, 0x1592, 0x696A, 0x0859, 0x0224, 0xFC30, 4},
	{22,  0, 0x1480, 0x53BD,  10, 14,  68, 100, 100,   0,  75, 0x4344, 0xBDF9, 0x0A5D, 0x0124, 0xF920, 3},
	{23,  0, 0x38AA, 0x0038,  12, 22, 255, 180, 210,   0, 130, 0x6369, 0xFF37, 0x0FBF, 0x0564, 0xFB52, 5},
	{24,  1, 0x068A, 0x97BD,  13, 28, 110, 255, 255,   0,  70, 0x3645, 0xBF7C, 0x06CD, 0x0445, 0xFC30, 4}, /* Atari ST Version 1.0 1987-12-08 1987-12-11: Ranges = 0x2645 */
	{25,  0, 0x38AA, 0x0000,  12, 22, 255, 180, 210,   0, 130, 0x6369, 0xFF37, 0x0FBF, 0x0564, 0xFB52, 5},
	{26,  0, 0x38AA, 0x0000,  12, 22, 255, 180, 210,   0, 130, 0x6369, 0xFF37, 0x0FBF, 0x0564, 0xFB52, 5}};

void DungeonMan::f150_mapCoordsAfterRelMovement(direction dir, int16 stepsForward, int16 stepsRight, int16 &posX, int16 &posY) {
	posX += _vm->_dirIntoStepCountEast[dir] * stepsForward;
	posY += _vm->_dirIntoStepCountNorth[dir] * stepsForward;
	turnDirRight(dir);
	posX += _vm->_dirIntoStepCountEast[dir] * stepsRight;
	posY += _vm->_dirIntoStepCountNorth[dir] * stepsRight;
}

DungeonMan::DungeonMan(DMEngine *dmEngine) : _vm(dmEngine), _rawDunFileData(NULL), _g277_dungeonMaps(NULL), _g276_dungeonRawMapData(NULL) {
	_g282_dungeonColumCount = 0;

	_g281_dungeonMapsFirstColumnIndex = nullptr;
	_g280_dungeonColumnsCumulativeSquareThingCount = nullptr;
	_g283_squareFirstThings = nullptr;
	_g260_dungeonTextData = nullptr;
	_g279_dungeonMapData = nullptr;

	for (int i = 0; i < 16; i++)
		_g284_thingData[i] = nullptr;

	_g308_partyDir = kDirNorth;
	_g306_partyMapX = 0;
	_g307_partyMapY = 0;
	_g309_partyMapIndex = 0;
	_g272_currMapIndex = 0;
	_g273_currMapWidth = 0;
	_g274_currMapHeight = 0;

	_g271_currMapData = nullptr;
	_g269_currMap = nullptr;
	_g270_currMapColCumulativeSquareFirstThingCount = nullptr;

	_vm->_g298_newGame = true;
	_vm->_g523_restartGameRequest = false;

	_rawDunFileDataSize = 0;
	_rawDunFileData = nullptr;

	_g278_dungeonFileHeader._dungeonId = 0;
	_g278_dungeonFileHeader._ornamentRandomSeed = 0;
	_g278_dungeonFileHeader._rawMapDataSize = 0;
	_g278_dungeonFileHeader._mapCount = 0;
	_g278_dungeonFileHeader._textDataWordCount = 0;
	_g278_dungeonFileHeader._partyStartDir = kDirNorth;
	_g278_dungeonFileHeader._partyStartPosX = 0;
	_g278_dungeonFileHeader._partyStartPosY = 0;
	_g278_dungeonFileHeader._squareFirstThingCount = 0;

	for (int i = 0; i < 16; i++)
		_g278_dungeonFileHeader._thingCounts[i] = 0;

	_g277_dungeonMaps = nullptr;
	_g276_dungeonRawMapData = nullptr;

	_g265_currMapInscriptionWallOrnIndex = 0;
	_g286_isFacingAlcove = false;
	_g287_isFacingViAltar = false;
	_g288_isFacingFountain = false;

	for (int j = 0; j < 6; j++)
		_g291_dungeonViewClickableBoxes[j].setToZero();
}

DungeonMan::~DungeonMan() {
	delete[] _rawDunFileData;
	delete[] _g277_dungeonMaps;
	delete[] _g281_dungeonMapsFirstColumnIndex;
	delete[] _g280_dungeonColumnsCumulativeSquareThingCount;
	delete[] _g283_squareFirstThings;
	delete[] _g260_dungeonTextData;
	delete[] _g279_dungeonMapData;
	for (uint16 i = 0; i < 16; ++i) {
		if (_g284_thingData[i])
			delete[] _g284_thingData[i][0];
		delete[] _g284_thingData[i];
	}
}

void DungeonMan::f455_decompressDungeonFile() {
	Common::File f;
	f.open("Dungeon.dat");
	if (f.readUint16BE() == 0x8104) {
		_rawDunFileDataSize = f.readUint32BE();
		delete[] _rawDunFileData;
		_rawDunFileData = new byte[_rawDunFileDataSize];
		f.readUint16BE();
		byte common[4];
		for (uint16 i = 0; i < 4; ++i)
			common[i] = f.readByte();
		byte lessCommon[16];
		for (uint16 i = 0; i < 16; ++i)
			lessCommon[i] = f.readByte();

		// start unpacking
		uint32 uncompIndex = 0;
		uint8 bitsUsedInWord = 0;
		uint16 wordBuff = f.readUint16BE();
		uint8 bitsLeftInByte = 8;
		byte byteBuff = f.readByte();
		while (uncompIndex < _rawDunFileDataSize) {
			while (bitsUsedInWord != 0) {
				uint8 shiftVal;
				if (f.eos()) {
					shiftVal = bitsUsedInWord;
					wordBuff <<= shiftVal;
				} else {
					shiftVal = MIN(bitsLeftInByte, bitsUsedInWord);
					wordBuff <<= shiftVal;
					wordBuff |= (byteBuff >> (8 - shiftVal));
					byteBuff <<= shiftVal;
					bitsLeftInByte -= shiftVal;
					if (!bitsLeftInByte) {
						byteBuff = f.readByte();
						bitsLeftInByte = 8;
					}
				}
				bitsUsedInWord -= shiftVal;
			}
			if (((wordBuff >> 15) & 1) == 0) {
				_rawDunFileData[uncompIndex++] = common[(wordBuff >> 13) & 3];
				bitsUsedInWord += 3;
			} else if (((wordBuff >> 14) & 3) == 2) {
				_rawDunFileData[uncompIndex++] = lessCommon[(wordBuff >> 10) & 15];
				bitsUsedInWord += 6;
			} else if (((wordBuff >> 14) & 3) == 3) {
				_rawDunFileData[uncompIndex++] = (wordBuff >> 6) & 255;
				bitsUsedInWord += 10;
			}
		}
	} else {
		warning("TODO: if the dungeon is uncompressed, read it here");
	}
	f.close();
}

byte g236_AdditionalThingCounts[16] = { // @ G0236_auc_Graphic559_AdditionalThingCounts{
	0,    /* Door */
	0,    /* Teleporter */
	0,    /* Text String */
	0,    /* Sensor */
	75,   /* Group */
	100,  /* Weapon */
	120,  /* Armour */
	0,    /* Scroll */
	5,    /* Potion */
	0,    /* Container */
	140,  /* Junk */
	0,    /* Unused */
	0,    /* Unused */
	0,    /* Unused */
	60,   /* Projectile */
	50    /* Explosion */
}; 

// this is the number of uint16s the data has to be stored, not the length of the data in dungeon.dat!
byte g235_ThingDataWordCount[16] = { // @ G0235_auc_Graphic559_ThingDataByteCount
	2,   /* Door */
	3,   /* Teleporter */
	2,   /* Text String */
	4,   /* Sensor */
	9,   /* Group */
	2,   /* Weapon */
	2,   /* Armour */
	2,   /* Scroll */
	2,   /* Potion */
	4,   /* Container */
	2,   /* Junk */
	0,   /* Unused */
	0,   /* Unused */
	0,   /* Unused */
	5,   /* Projectile */
	2    /* Explosion */
}; 

const Thing Thing::_none(0); // @ C0xFFFF_THING_NONE
const Thing Thing::_endOfList(0xFFFE); // @ C0xFFFE_THING_ENDOFLIST
const Thing Thing::_firstExplosion(0xFF80); // @ C0xFF80_THING_FIRST_EXPLOSION            
const Thing Thing::_explFireBall(0xFF80); // @ C0xFF80_THING_EXPLOSION_FIREBALL         
const Thing Thing::_explSlime(0xFF81); // @ C0xFF81_THING_EXPLOSION_SLIME            
const Thing Thing::_explLightningBolt(0xFF82); // @ C0xFF82_THING_EXPLOSION_LIGHTNING_BOLT   
const Thing Thing::_explHarmNonMaterial(0xFF83); // @ C0xFF83_THING_EXPLOSION_HARM_NON_MATERIAL
const Thing Thing::_explOpenDoor(0xFF84); // @ C0xFF84_THING_EXPLOSION_OPEN_DOOR        
const Thing Thing::_explPoisonBolt(0xFF86); // @ C0xFF86_THING_EXPLOSION_POISON_BOLT      
const Thing Thing::_explPoisonCloud(0xFF87); // @ C0xFF87_THING_EXPLOSION_POISON_CLOUD     
const Thing Thing::_explSmoke(0xFFA8); // @ C0xFFA8_THING_EXPLOSION_SMOKE            
const Thing Thing::_explFluxcage(0xFFB2); // @ C0xFFB2_THING_EXPLOSION_FLUXCAGE         
const Thing Thing::_explRebirthStep1(0xFFE4); // @ C0xFFE4_THING_EXPLOSION_REBIRTH_STEP1    
const Thing Thing::_explRebirthStep2(0xFFE5); // @ C0xFFE5_THING_EXPLOSION_REBIRTH_STEP2    
const Thing Thing::_party(0xFFFF); // @ C0xFFFF_THING_PARTY          

void DungeonMan::f434_loadDungeonFile() {
	if (_vm->_g298_newGame)
		f455_decompressDungeonFile();

	Common::MemoryReadStream dunDataStream(_rawDunFileData, _rawDunFileDataSize, DisposeAfterUse::NO);

	// initialize _g278_dungeonFileHeader
	_g278_dungeonFileHeader._dungeonId = _g278_dungeonFileHeader._ornamentRandomSeed = dunDataStream.readUint16BE();
	_g278_dungeonFileHeader._rawMapDataSize = dunDataStream.readUint16BE();
	_g278_dungeonFileHeader._mapCount = dunDataStream.readByte();
	dunDataStream.readByte(); // discard 1 byte
	_g278_dungeonFileHeader._textDataWordCount = dunDataStream.readUint16BE();
	uint16 partyPosition = dunDataStream.readUint16BE();
	_g278_dungeonFileHeader._partyStartDir = (direction)((partyPosition >> 10) & 3);
	_g278_dungeonFileHeader._partyStartPosY = (partyPosition >> 5) & 0x1F;
	_g278_dungeonFileHeader._partyStartPosX = (partyPosition >> 0) & 0x1F;
	_g278_dungeonFileHeader._squareFirstThingCount = dunDataStream.readUint16BE();
	for (uint16 i = 0; i < k16_ThingTypeTotal; ++i)
		_g278_dungeonFileHeader._thingCounts[i] = dunDataStream.readUint16BE();

	// init party position and mapindex
	if (_vm->_g298_newGame) {
		_g308_partyDir = _g278_dungeonFileHeader._partyStartDir;
		_g306_partyMapX = _g278_dungeonFileHeader._partyStartPosX;
		_g307_partyMapY = _g278_dungeonFileHeader._partyStartPosY;
		_g309_partyMapIndex = 0;
	}

	// load map data
	delete[] _g277_dungeonMaps;
	_g277_dungeonMaps = new Map[_g278_dungeonFileHeader._mapCount];
	for (uint16 i = 0; i < _g278_dungeonFileHeader._mapCount; ++i) {
		_g277_dungeonMaps[i]._rawDunDataOffset = dunDataStream.readUint16BE();
		dunDataStream.readUint32BE(); // discard 4 bytes
		_g277_dungeonMaps[i]._offsetMapX = dunDataStream.readByte();
		_g277_dungeonMaps[i]._offsetMapY = dunDataStream.readByte();

		uint16 tmp = dunDataStream.readUint16BE();
		_g277_dungeonMaps[i]._height = tmp >> 11;
		_g277_dungeonMaps[i]._width = (tmp >> 6) & 0x1F;
		_g277_dungeonMaps[i]._level = tmp & 0x1F; // Only used in DMII

		tmp = dunDataStream.readUint16BE();
		_g277_dungeonMaps[i]._randFloorOrnCount = tmp >> 12;
		_g277_dungeonMaps[i]._floorOrnCount = (tmp >> 8) & 0xF;
		_g277_dungeonMaps[i]._randWallOrnCount = (tmp >> 4) & 0xF;
		_g277_dungeonMaps[i]._wallOrnCount = tmp & 0xF;

		tmp = dunDataStream.readUint16BE();
		_g277_dungeonMaps[i]._difficulty = tmp >> 12;
		_g277_dungeonMaps[i]._creatureTypeCount = (tmp >> 4) & 0xF;
		_g277_dungeonMaps[i]._doorOrnCount = tmp & 0xF;

		tmp = dunDataStream.readUint16BE();
		_g277_dungeonMaps[i]._doorSet1 = (tmp >> 12) & 0xF;
		_g277_dungeonMaps[i]._doorSet0 = (tmp >> 8) & 0xF;
		_g277_dungeonMaps[i]._wallSet = (WallSet)((tmp >> 4) & 0xF);
		_g277_dungeonMaps[i]._floorSet = (FloorSet)(tmp & 0xF);
	}

	// TODO: ??? is this - begin
	delete[] _g281_dungeonMapsFirstColumnIndex;
	_g281_dungeonMapsFirstColumnIndex = new uint16[_g278_dungeonFileHeader._mapCount];
	uint16 columCount = 0;
	for (uint16 i = 0; i < _g278_dungeonFileHeader._mapCount; ++i) {
		_g281_dungeonMapsFirstColumnIndex[i] = columCount;
		columCount += _g277_dungeonMaps[i]._width + 1;
	}
	_g282_dungeonColumCount = columCount;
	// TODO: ??? is this - end


	uint32 actualSquareFirstThingCount = _g278_dungeonFileHeader._squareFirstThingCount;
	if (_vm->_g298_newGame) // TODO: what purpose does this serve?
		_g278_dungeonFileHeader._squareFirstThingCount += 300;

	// TODO: ??? is this - begin
	delete[] _g280_dungeonColumnsCumulativeSquareThingCount;
	_g280_dungeonColumnsCumulativeSquareThingCount = new uint16[columCount];
	for (uint16 i = 0; i < columCount; ++i)
		_g280_dungeonColumnsCumulativeSquareThingCount[i] = dunDataStream.readUint16BE();
	// TODO: ??? is this - end

	// TODO: ??? is this - begin
	delete[] _g283_squareFirstThings;
	_g283_squareFirstThings = new Thing[_g278_dungeonFileHeader._squareFirstThingCount];
	for (uint16 i = 0; i < actualSquareFirstThingCount; ++i)
		_g283_squareFirstThings[i].set(dunDataStream.readUint16BE());
	if (_vm->_g298_newGame)
		for (uint16 i = 0; i < 300; ++i)
			_g283_squareFirstThings[actualSquareFirstThingCount + i] = Thing::_none;

	// TODO: ??? is this - end

	// load text data
	delete[] _g260_dungeonTextData;
	_g260_dungeonTextData = new uint16[_g278_dungeonFileHeader._textDataWordCount];
	for (uint16 i = 0; i < _g278_dungeonFileHeader._textDataWordCount; ++i)
		_g260_dungeonTextData[i] = dunDataStream.readUint16BE();

	// TODO: ??? what this
	if (_vm->_g298_newGame)
		_vm->_timeline->_g369_eventMaxCount = 100;

	// load things
	for (uint16 thingType = k0_DoorThingType; thingType < k16_ThingTypeTotal; ++thingType) {
		uint16 thingCount = _g278_dungeonFileHeader._thingCounts[thingType];
		if (_vm->_g298_newGame) {
			_g278_dungeonFileHeader._thingCounts[thingType] = MIN((thingType == k15_ExplosionThingType) ? 768 : 1024, thingCount + g236_AdditionalThingCounts[thingType]);
		}
		uint16 thingStoreWordCount = g235_ThingDataWordCount[thingType];

		if (thingStoreWordCount == 0)
			continue;

		if (_g284_thingData[thingType]) {
			delete[] _g284_thingData[thingType][0];
			delete[] _g284_thingData[thingType];
		}
		_g284_thingData[thingType] = new uint16*[_g278_dungeonFileHeader._thingCounts[thingType]];
		_g284_thingData[thingType][0] = new uint16[_g278_dungeonFileHeader._thingCounts[thingType] * thingStoreWordCount];
		for (uint16 i = 0; i < _g278_dungeonFileHeader._thingCounts[thingType]; ++i)
			_g284_thingData[thingType][i] = _g284_thingData[thingType][0] + i * thingStoreWordCount;

		if (thingType == k4_GroupThingType) {
			for (uint16 i = 0; i < thingCount; ++i)
				for (uint16 j = 0; j < thingStoreWordCount; ++j) {
					if (j == 2 || j == 3)
						_g284_thingData[thingType][i][j] = dunDataStream.readByte();
					else
						_g284_thingData[thingType][i][j] = dunDataStream.readUint16BE();
				}
		} else if (thingType == k14_ProjectileThingType) {
			for (uint16 i = 0; i < thingCount; ++i) {
				_g284_thingData[thingType][i][0] = dunDataStream.readUint16BE();
				_g284_thingData[thingType][i][1] = dunDataStream.readUint16BE();
				_g284_thingData[thingType][i][2] = dunDataStream.readByte();
				_g284_thingData[thingType][i][3] = dunDataStream.readByte();
				_g284_thingData[thingType][i][4] = dunDataStream.readUint16BE();
			}
		} else {
			for (uint16 i = 0; i < thingCount; ++i) {
				for (uint16 j = 0; j < thingStoreWordCount; ++j)
					_g284_thingData[thingType][i][j] = dunDataStream.readUint16BE();
			}
		}

		if (_vm->_g298_newGame) {
			if ((thingType == k4_GroupThingType) || thingType >= k14_ProjectileThingType)
				_vm->_timeline->_g369_eventMaxCount += _g278_dungeonFileHeader._thingCounts[thingType];
			for (uint16 i = 0; i < g236_AdditionalThingCounts[thingType]; ++i) {
				_g284_thingData[thingType][thingCount + i][0] = Thing::_none.toUint16();
			}
		}
	}

	// load map data
	if (!_vm->_g523_restartGameRequest)
		_g276_dungeonRawMapData = _rawDunFileData + dunDataStream.pos();


	if (!_vm->_g523_restartGameRequest) {
		uint8 mapCount = _g278_dungeonFileHeader._mapCount;
		delete[] _g279_dungeonMapData;
		_g279_dungeonMapData = new byte**[_g282_dungeonColumCount + mapCount];
		byte **colFirstSquares = (byte**)_g279_dungeonMapData + mapCount;
		for (uint8 i = 0; i < mapCount; ++i) {
			_g279_dungeonMapData[i] = colFirstSquares;
			byte *square = _g276_dungeonRawMapData + _g277_dungeonMaps[i]._rawDunDataOffset;
			*colFirstSquares++ = square;
			for (uint16 w = 1; w <= _g277_dungeonMaps[i]._width; ++w) {
				square += _g277_dungeonMaps[i]._height + 1;
				*colFirstSquares++ = square;
			}
		}
	}
}

void DungeonMan::f173_setCurrentMap(uint16 mapIndex) {
	_g272_currMapIndex = mapIndex;
	_g271_currMapData = _g279_dungeonMapData[mapIndex];
	_g269_currMap = _g277_dungeonMaps + mapIndex;
	_g273_currMapWidth = _g277_dungeonMaps[mapIndex]._width + 1;
	_g274_currMapHeight = _g277_dungeonMaps[mapIndex]._height + 1;
	_g270_currMapColCumulativeSquareFirstThingCount
		= &_g280_dungeonColumnsCumulativeSquareThingCount[_g281_dungeonMapsFirstColumnIndex[mapIndex]];
}

void DungeonMan::f174_setCurrentMapAndPartyMap(uint16 mapIndex) {
	f173_setCurrentMap(mapIndex);

	byte *metaMapData = _g271_currMapData[_g273_currMapWidth - 1] + _g274_currMapHeight;
	_vm->_displayMan->_g264_currMapAllowedCreatureTypes = metaMapData;

	metaMapData += _g269_currMap->_creatureTypeCount;
	memcpy(_vm->_displayMan->_g261_currMapWallOrnIndices, metaMapData, _g269_currMap->_wallOrnCount);

	metaMapData += _g269_currMap->_wallOrnCount;
	memcpy(_vm->_displayMan->_g262_currMapFloorOrnIndices, metaMapData, _g269_currMap->_floorOrnCount);

	metaMapData += _g269_currMap->_wallOrnCount;
	memcpy(_vm->_displayMan->_g263_currMapDoorOrnIndices, metaMapData, _g269_currMap->_doorOrnCount);

	_g265_currMapInscriptionWallOrnIndex = _g269_currMap->_wallOrnCount;
	_vm->_displayMan->_g261_currMapWallOrnIndices[_g265_currMapInscriptionWallOrnIndex] = k0_WallOrnInscription;
}


Square DungeonMan::f151_getSquare(int16 mapX, int16 mapY) {
	bool isInXBounds = (mapX >= 0) && (mapX < _g273_currMapWidth);
	bool isInYBounds = (mapY >= 0) && (mapY < _g274_currMapHeight);

	if (isInXBounds && isInYBounds)
		return Square(_g271_currMapData[mapX][mapY]);


	Square tmpSquare;
	if (isInYBounds) {
		tmpSquare.set(_g271_currMapData[0][mapY]);
		if (mapX == -1 && (tmpSquare.getType() == k1_CorridorElemType || tmpSquare.getType() == k2_PitElemType))
			return Square(k0_WallElemType).set(k0x0004_WallEastRandOrnAllowed);

		tmpSquare.set(_g271_currMapData[_g273_currMapWidth - 1][mapY]);
		if (mapX == _g273_currMapWidth && (tmpSquare.getType() == k1_CorridorElemType || tmpSquare.getType() == k2_PitElemType))
			return Square(k0_WallElemType).set(k0x0001_WallWestRandOrnAllowed);
	} else if (isInXBounds) {
		tmpSquare.set(_g271_currMapData[mapX][0]);
		if (mapY == -1 && (tmpSquare.getType() == k1_CorridorElemType || tmpSquare.getType() == k2_PitElemType))
			return Square(k0_WallElemType).set(k0x0002_WallSouthRandOrnAllowed);

		tmpSquare.set(_g271_currMapData[mapX][_g274_currMapHeight - 1]);
		if (mapY == _g274_currMapHeight && (tmpSquare.getType() == k1_CorridorElemType || tmpSquare.getType() == k2_PitElemType))
			return Square((k0_WallElemType << 5) | k0x0008_WallNorthRandOrnAllowed);
	}

	return Square(k0_WallElemType);
}

Square DungeonMan::f152_getRelSquare(direction dir, int16 stepsForward, int16 stepsRight, int16 posX, int16 posY) {
	f150_mapCoordsAfterRelMovement(dir, stepsForward, stepsForward, posX, posY);
	return f151_getSquare(posX, posY);
}

int16 DungeonMan::f160_getSquareFirstThingIndex(int16 mapX, int16 mapY) {
	if (mapX < 0 || mapX >= _g273_currMapWidth || mapY < 0 || mapY >= _g274_currMapHeight || !Square(_g271_currMapData[mapX][mapY]).get(k0x0010_ThingListPresent))
		return -1;

	int16 y = 0;
	uint16 index = _g270_currMapColCumulativeSquareFirstThingCount[mapX];
	byte* square = _g271_currMapData[mapX];
	while (y++ != mapY)
		if (Square(*square++).get(k0x0010_ThingListPresent))
			index++;

	return index;
}

Thing DungeonMan::f161_getSquareFirstThing(int16 mapX, int16 mapY) {
	int16 index = f160_getSquareFirstThingIndex(mapX, mapY);
	if (index == -1)
		return Thing::_endOfList;
	return _g283_squareFirstThings[index];
}


// TODO: get rid of the GOTOs
void DungeonMan::f172_setSquareAspect(uint16 *aspectArray, direction dir, int16 mapX, int16 mapY) {	// complete, except where marked
	_vm->_displayMan->_g289_championPortraitOrdinal = 0; // BUG0_75, possible fix

	for (uint16 i = 0; i < 5; ++i)
		aspectArray[i] = 0;

	Thing thing = f161_getSquareFirstThing(mapX, mapY);
	Square square = f151_getSquare(mapX, mapY);

	aspectArray[k0_ElemAspect] = square.getType();

	bool leftOrnAllowed = false;
	bool rightOrnAllowed = false;
	bool frontOrnAllowed = false;
	bool squareIsFakeWall = false;
	bool footPrintsAllowed = false;
	switch (square.getType()) {
	case k0_WallElemType:
		switch (dir) {
		case kDirNorth:
			leftOrnAllowed = square.get(k0x0004_WallEastRandOrnAllowed);
			frontOrnAllowed = square.get(k0x0002_WallSouthRandOrnAllowed);
			rightOrnAllowed = square.get(k0x0001_WallWestRandOrnAllowed);
			break;
		case kDirEast:
			leftOrnAllowed = square.get(k0x0002_WallSouthRandOrnAllowed);
			frontOrnAllowed = square.get(k0x0001_WallWestRandOrnAllowed);
			rightOrnAllowed = square.get(k0x0008_WallNorthRandOrnAllowed);
			break;
		case kDirSouth:
			leftOrnAllowed = square.get(k0x0001_WallWestRandOrnAllowed);
			frontOrnAllowed = square.get(k0x0008_WallNorthRandOrnAllowed);
			rightOrnAllowed = square.get(k0x0004_WallEastRandOrnAllowed);
			break;
		case kDirWest:
			leftOrnAllowed = square.get(k0x0008_WallNorthRandOrnAllowed);
			frontOrnAllowed = square.get(k0x0004_WallEastRandOrnAllowed);
			rightOrnAllowed = square.get(k0x0002_WallSouthRandOrnAllowed);
			break;
		default:
			break;
		}

T0172010_ClosedFakeWall:
		f171_setSquareAspectOrnOrdinals(aspectArray, leftOrnAllowed, frontOrnAllowed, rightOrnAllowed, dir, mapX, mapY, squareIsFakeWall);

		while ((thing != Thing::_endOfList) && (thing.getType() <= k3_SensorThingType)) {
			int16 sideIndex = (thing.getCell() - dir) & 3;
			if (sideIndex) {
				if (thing.getType() == k2_TextstringType) {
					if (TextString(f156_getThingData(thing)).isVisible()) {
						aspectArray[sideIndex + 1] = _g265_currMapInscriptionWallOrnIndex + 1;
						_vm->_displayMan->_g290_inscriptionThing = thing; // BUG0_76
					}
				} else {
					Sensor sensor(f156_getThingData(thing));
					aspectArray[sideIndex + 1] = sensor.getOrnOrdinal();
					if (sensor.getType() == k127_SensorWallChampionPortrait) {
						_vm->_displayMan->_g289_championPortraitOrdinal = _vm->M0_indexToOrdinal(sensor.getData());
					}
				}
			}
			thing = f159_getNextThing(thing);
		}
		if (squareIsFakeWall && (_g306_partyMapX != mapX) && (_g307_partyMapY != mapY)) {
			aspectArray[k1_FirstGroupOrObjectAspect] = Thing::_endOfList.toUint16();
			return;
		}
		break;
	case k2_PitElemType:
		if (square.get(k0x0008_PitOpen)) {
			aspectArray[k2_PitInvisibleAspect] = square.get(k0x0004_PitInvisible);
			footPrintsAllowed = square.toByte() & 1;
		} else {
			aspectArray[k0_ElemAspect] = k1_CorridorElemType;
			footPrintsAllowed = true;
		}
		goto T0172030_Pit;
	case k6_FakeWallElemType:
		if (!square.get(k0x0004_FakeWallOpen)) {
			aspectArray[k0_ElemAspect] = k0_WallElemType;
			leftOrnAllowed = rightOrnAllowed = frontOrnAllowed = square.get(k0x0008_FakeWallRandOrnOrFootPAllowed);
			squareIsFakeWall = true;
			goto T0172010_ClosedFakeWall;
		}
		aspectArray[k0_WallElemType] = k1_CorridorElemType;
		footPrintsAllowed = square.get(k0x0008_FakeWallRandOrnOrFootPAllowed);
		square = Square(footPrintsAllowed ? 8 : 0);
		// intentional fallthrough
	case k1_CorridorElemType:
		aspectArray[k4_FloorOrnOrdAspect] = f170_getRandomOrnOrdinal(square.get(k0x0008_CorridorRandOrnAllowed), _g269_currMap->_randFloorOrnCount, mapX, mapY, 30);
T0172029_Teleporter:
		footPrintsAllowed = true;
T0172030_Pit:
		while ((thing != Thing::_endOfList) && (thing.getType() <= k3_SensorThingType)) {
			if (thing.getType() == k3_SensorThingType)
				aspectArray[k4_FloorOrnOrdAspect] = Sensor(f156_getThingData(thing)).getOrnOrdinal();
			thing = f159_getNextThing(thing);
		}
		goto T0172049_Footprints;
	case k5_TeleporterElemType:
		aspectArray[k2_TeleporterVisibleAspect] = square.get(k0x0008_TeleporterOpen) && square.get(k0x0004_TeleporterVisible);
		goto T0172029_Teleporter;
	case k3_StairsElemType:
		aspectArray[k0_ElemAspect] = ((square.get(k0x0008_StairsNorthSouthOrient) >> 3) == (isOrientedWestEast(dir) ? 1 : 0)) ? k18_StairsSideElemType : k19_StairsFrontElemType;
		aspectArray[k2_StairsUpAspect] = square.get(k0x0004_StairsUp);
		footPrintsAllowed = false;
		goto T0172046_Stairs;
	case k4_DoorElemType:
		if ((square.get(k0x0008_DoorNorthSouthOrient) >> 3) == (isOrientedWestEast(dir) ? 1 : 0)) {
			aspectArray[k0_ElemAspect] = k16_DoorSideElemType;
		} else {
			aspectArray[k0_ElemAspect] = k17_DoorFrontElemType;
			aspectArray[k2_DoorStateAspect] = square.getDoorState();
			aspectArray[k3_DoorThingIndexAspect] = f161_getSquareFirstThing(mapX, mapY).getIndex();
		}
		footPrintsAllowed = true;
T0172046_Stairs:
		while ((thing != Thing::_endOfList) && (thing.getType() <= k3_SensorThingType))
			thing = f159_getNextThing(thing);
T0172049_Footprints:
		unsigned char scentOrdinal; // see next line comment
		if (footPrintsAllowed) // TODO: I skipped some party query code, must come back later and complete
			aspectArray[k4_FloorOrnOrdAspect] &= k0x8000_FootprintsAspect;
		break;
	default:
		break;
	}
	aspectArray[k1_FirstGroupOrObjectAspect] = thing.toUint16();
}

void DungeonMan::f171_setSquareAspectOrnOrdinals(uint16 *aspectArray, bool leftAllowed, bool frontAllowed, bool rightAllowed, direction dir,
											int16 mapX, int16 mapY, bool isFakeWall) {
	int16 ornCount = _g269_currMap->_randWallOrnCount;

	turnDirRight(dir);
	aspectArray[k2_RightWallOrnOrdAspect] = f170_getRandomOrnOrdinal(leftAllowed, ornCount, mapX, ++mapY * (dir + 1), 30);
	turnDirRight(dir);
	aspectArray[k3_FrontWallOrnOrdAspect] = f170_getRandomOrnOrdinal(frontAllowed, ornCount, mapX, ++mapY * (dir + 1), 30);
	turnDirRight(dir);
	aspectArray[k4_LeftWallOrnOrdAspect] = f170_getRandomOrnOrdinal(rightAllowed, ornCount, mapX, ++mapY * (dir + 1), 30);

	if (isFakeWall || mapX < 0 || mapX >= _g273_currMapWidth || mapY < 0 || mapY >= _g274_currMapHeight) {
		for (uint16 i = k2_RightWallOrnOrdAspect; i <= k4_LeftWallOrnOrdAspect; ++i) {
			if (f149_isWallOrnAnAlcove(_vm->M1_ordinalToIndex(aspectArray[i])))
				aspectArray[i] = 0;
		}
	}
}

int16 DungeonMan::f170_getRandomOrnOrdinal(bool allowed, int16 count, int16 mapX, int16 mapY, int16 modulo) {
	int16 index = (((((2000 + (mapX << 5) + mapY) * 31417) >> 1)
					+ (3000 + (_g272_currMapIndex << 6) + _g273_currMapWidth + _g274_currMapHeight) * 11
					+ _g278_dungeonFileHeader._ornamentRandomSeed) >> 2) % modulo;
	if (allowed && index < count)
		return _vm->M0_indexToOrdinal(index);
	return 0;
}


bool DungeonMan::f149_isWallOrnAnAlcove(int16 wallOrnIndex) {
	if (wallOrnIndex >= 0)
		for (uint16 i = 0; i < k3_AlcoveOrnCount; ++i)
			if (_vm->_displayMan->_g267_currMapAlcoveOrnIndices[i] == wallOrnIndex)
				return true;
	return false;
}

uint16 *DungeonMan::f156_getThingData(Thing thing) {
	return _g284_thingData[thing.getType()][thing.getIndex()];
}

uint16* DungeonMan::f157_getSquareFirstThingData(int16 mapX, int16 mapY) {
	return f156_getThingData(f161_getSquareFirstThing(mapX, mapY));
}

Thing DungeonMan::f159_getNextThing(Thing thing) {
	return Thing(f156_getThingData(thing)[0]); // :)
}

char g255_MessageAndScrollEscReplacementStrings[32][8] = { // @ G0255_aac_Graphic559_MessageAndScrollEscapeReplacementStrings
	{'x',  0,  0,  0, 0, 0, 0, 0}, /* Atari ST Version 1.0 1987-12-08 1987-12-11 1.1 1.2EN 1.2GE: { '?',  0,  0,  0, 0, 0, 0, 0 }, */
	{'y',  0,  0,  0, 0, 0, 0, 0}, /* Atari ST Version 1.0 1987-12-08 1987-12-11 1.1 1.2EN 1.2GE: { '!',  0,  0,  0, 0, 0, 0, 0 }, */
	{'T','H','E',' ', 0, 0, 0, 0},
	{'Y','O','U',' ', 0, 0, 0, 0},
	{'z',  0,  0,  0, 0, 0, 0, 0}, /* Atari ST Version 1.0 1987-12-08 1987-12-11 1.1 1.2EN 1.2GE: { 0,  0,  0,  0, 0, 0, 0, 0 }, */
	{'{',  0,  0,  0, 0, 0, 0, 0}, /* Atari ST Version 1.0 1987-12-08 1987-12-11 1.1 1.2EN 1.2GE: { 0,  0,  0,  0, 0, 0, 0, 0 }, */
	{'|',  0,  0,  0, 0, 0, 0, 0}, /* Atari ST Version 1.0 1987-12-08 1987-12-11 1.1 1.2EN 1.2GE: { 0,  0,  0,  0, 0, 0, 0, 0 }, */
	{'}',  0,  0,  0, 0, 0, 0, 0}, /* Atari ST Version 1.0 1987-12-08 1987-12-11 1.1 1.2EN 1.2GE: { 0,  0,  0,  0, 0, 0, 0, 0 }, */
	{'~',  0,  0,  0, 0, 0, 0, 0}, /* Atari ST Version 1.0 1987-12-08 1987-12-11 1.1 1.2EN 1.2GE: { 0,  0,  0,  0, 0, 0, 0, 0 }, */
	{'',  0,  0,  0, 0, 0, 0, 0}, /* Atari ST Version 1.0 1987-12-08 1987-12-11 1.1 1.2EN 1.2GE: { 0,  0,  0,  0, 0, 0, 0, 0 }, */
	{0,  0,  0,  0, 0, 0, 0, 0},
	{0,  0,  0,  0, 0, 0, 0, 0},
	{0,  0,  0,  0, 0, 0, 0, 0},
	{0,  0,  0,  0, 0, 0, 0, 0},
	{0,  0,  0,  0, 0, 0, 0, 0},
	{0,  0,  0,  0, 0, 0, 0, 0},
	{0,  0,  0,  0, 0, 0, 0, 0},
	{0,  0,  0,  0, 0, 0, 0, 0},
	{0,  0,  0,  0, 0, 0, 0, 0},
	{0,  0,  0,  0, 0, 0, 0, 0},
	{0,  0,  0,  0, 0, 0, 0, 0},
	{0,  0,  0,  0, 0, 0, 0, 0},
	{0,  0,  0,  0, 0, 0, 0, 0},
	{0,  0,  0,  0, 0, 0, 0, 0},
	{0,  0,  0,  0, 0, 0, 0, 0},
	{0,  0,  0,  0, 0, 0, 0, 0},
	{0,  0,  0,  0, 0, 0, 0, 0},
	{0,  0,  0,  0, 0, 0, 0, 0},
	{0,  0,  0,  0, 0, 0, 0, 0},
	{0,  0,  0,  0, 0, 0, 0, 0},
	{0,  0,  0,  0, 0, 0, 0, 0},
	{0,  0,  0,  0, 0, 0, 0, 0}};
char g256_EscReplacementCharacters[32][2] = { // @ G0256_aac_Graphic559_EscapeReplacementCharacters
	{'a', 0},
	{'b', 0},
	{'c', 0},
	{'d', 0},
	{'e', 0},
	{'f', 0},
	{'g', 0},
	{'h', 0},
	{'i', 0},
	{'j', 0},
	{'k', 0},
	{'l', 0},
	{'m', 0},
	{'n', 0},
	{'o', 0},
	{'p', 0},
	{'q', 0},
	{'r', 0},
	{'s', 0},
	{'t', 0},
	{'u', 0},
	{'v', 0},
	{'w', 0},
	{'x', 0},
	{'0', 0},
	{'1', 0},
	{'2', 0},
	{'3', 0},
	{'4', 0},
	{'5', 0},
	{'6', 0},
	{'7', 0}};
char g257_InscriptionEscReplacementStrings[32][8] = { // @ G0257_aac_Graphic559_InscriptionEscapeReplacementStrings
	{28,  0,  0,  0, 0, 0, 0, 0}, /* Atari ST Version 1.0 1987-12-08 1987-12-11 1.1 1.2EN 1.2GE: { 0,  0,  0,  0, 0, 0, 0, 0 }, */
	{29,  0,  0,  0, 0, 0, 0, 0}, /* Atari ST Version 1.0 1987-12-08 1987-12-11 1.1 1.2EN 1.2GE: { 0,  0,  0,  0, 0, 0, 0, 0 }, */
	{19,  7,  4, 26, 0, 0, 0, 0},
	{24, 14, 20, 26, 0, 0, 0, 0},
	{30,  0,  0,  0, 0, 0, 0, 0}, /* Atari ST Version 1.0 1987-12-08 1987-12-11 1.1 1.2EN 1.2GE: { 0,  0,  0,  0, 0, 0, 0, 0 }, */
	{31,  0,  0,  0, 0, 0, 0, 0}, /* Atari ST Version 1.0 1987-12-08 1987-12-11 1.1 1.2EN 1.2GE: { 0,  0,  0,  0, 0, 0, 0, 0 }, */
	{32,  0,  0,  0, 0, 0, 0, 0}, /* Atari ST Version 1.0 1987-12-08 1987-12-11 1.1 1.2EN 1.2GE: { 0,  0,  0,  0, 0, 0, 0, 0 }, */
	{33,  0,  0,  0, 0, 0, 0, 0}, /* Atari ST Version 1.0 1987-12-08 1987-12-11 1.1 1.2EN 1.2GE: { 0,  0,  0,  0, 0, 0, 0, 0 }, */
	{34,  0,  0,  0, 0, 0, 0, 0}, /* Atari ST Version 1.0 1987-12-08 1987-12-11 1.1 1.2EN 1.2GE: { 0,  0,  0,  0, 0, 0, 0, 0 }, */
	{35,  0,  0,  0, 0, 0, 0, 0}, /* Atari ST Version 1.0 1987-12-08 1987-12-11 1.1 1.2EN 1.2GE: { 0,  0,  0,  0, 0, 0, 0, 0 }, */
	{0,  0,  0,  0, 0, 0, 0, 0},
	{0,  0,  0,  0, 0, 0, 0, 0},
	{0,  0,  0,  0, 0, 0, 0, 0},
	{0,  0,  0,  0, 0, 0, 0, 0},
	{0,  0,  0,  0, 0, 0, 0, 0},
	{0,  0,  0,  0, 0, 0, 0, 0},
	{0,  0,  0,  0, 0, 0, 0, 0},
	{0,  0,  0,  0, 0, 0, 0, 0},
	{0,  0,  0,  0, 0, 0, 0, 0},
	{0,  0,  0,  0, 0, 0, 0, 0},
	{0,  0,  0,  0, 0, 0, 0, 0},
	{0,  0,  0,  0, 0, 0, 0, 0},
	{0,  0,  0,  0, 0, 0, 0, 0},
	{0,  0,  0,  0, 0, 0, 0, 0},
	{0,  0,  0,  0, 0, 0, 0, 0},
	{0,  0,  0,  0, 0, 0, 0, 0},
	{0,  0,  0,  0, 0, 0, 0, 0},
	{0,  0,  0,  0, 0, 0, 0, 0},
	{0,  0,  0,  0, 0, 0, 0, 0},
	{0,  0,  0,  0, 0, 0, 0, 0},
	{0,  0,  0,  0, 0, 0, 0, 0},
	{0,  0,  0,  0, 0, 0, 0, 0}};


void DungeonMan::f168_decodeText(char *destString, Thing thing, TextType type) {
	char sepChar;
	TextString textString(_g284_thingData[k2_TextstringType][thing.getIndex()]);
	if ((textString.isVisible()) || (type & k0x8000_DecodeEvenIfInvisible)) {
		type = (TextType)(type & ~k0x8000_DecodeEvenIfInvisible);
		if (type == k1_TextTypeMessage) {
			*destString++ = '\n';
			sepChar = ' ';
		} else if (type == k0_TextTypeInscription) {
			sepChar = (char)0x80;
		} else {
			sepChar = '\n';
		}
		uint16 codeCounter = 0;
		int16 escChar = 0;
		uint16 *codeWord = _g260_dungeonTextData + textString.getWordOffset();
		uint16 code = 0, codes = 0;
		char *escReplString = nullptr;
		for (;;) { /*infinite loop*/
			if (!codeCounter) {
				codes = *codeWord++;
				code = (codes >> 10) & 0x1F;
			} else if (codeCounter == 1) {
				code = (codes >> 5) & 0x1F;
			} else {
				code = codes & 0x1F;
			}
			++codeCounter;
			codeCounter %= 3;

			if (escChar) {
				*destString = '\0';
				if (escChar == 30) {
					if (type != k0_TextTypeInscription) {
						escReplString = g255_MessageAndScrollEscReplacementStrings[code];
					} else {
						escReplString = g257_InscriptionEscReplacementStrings[code];
					}
				} else {
					escReplString = g256_EscReplacementCharacters[code];
				}
				strcat(destString, escReplString);
				destString += strlen(escReplString);
				escChar = 0;
			} else if (code < 28) {
				if (type != k0_TextTypeInscription) {
					if (code == 26) {
						code = ' ';
					} else if (code == 27) {
						code = '.';
					} else {
						code += 'A';
					}
				}
				*destString++ = code;
			} else if (code == 28) {
				*destString++ = sepChar;
			} else if (code <= 30) {
				escChar = code;
			} else {
				break;
			}
		}
	}
	*destString = ((type == k0_TextTypeInscription) ? 0x81 : '\0');
}


uint16 DungeonMan::f140_getObjectWeight(Thing thing) {
	static const uint16 g241_junkInfo[] = { // @ G0241_auc_Graphic559_JunkInfo
		// COMPASS - WATERSKIN - JEWEL SYMAL - ILLUMULET - ASHES
		1, 3, 2, 2, 4,
		// BONES - COPPER COIN - SILVER COIN - GOLD COIN - IRON KEY
		15, 1, 1, 1, 2,
		// KEY OF B - SOLID KEY - SQUARE KEY - TOURQUOISE KEY - CROSS KEY
		1, 1, 1, 1, 1,
		// ONYX KEY - SKELETON KEY - GOLD KEY - WINGED KEY - TOPAZ KEY
		1, 1, 1, 1, 1,
		// SAPPHIRE KEY - EMERALD KEY - RUBY KEY - RA KEY - MASTER KEY
		1, 1, 1, 1, 1,
		// BOULDER - BLUE GEM - ORANGE GEM - GREEN GEM - APPLE
		81, 2, 3, 2, 4,
		// CORN - BREAD - CHEESE - SCREAMER SLICE - WORM ROUND
		4, 3, 8, 5, 11,
		// DRUMSTICK - DRAGON STEAK - GEM OF AGES - EKKHARD CROSS - MOONSTONE
		4, 6, 2, 3, 2,
		// THE HELLION - PENDANT FERAL - MAGICAL BOX - MAGICAL BOX - MIRROR OF DAWN
		2, 2, 6, 9, 3,
		// ROPE - RABBIT'S FOOT - CORBAMITE - CHOKER - LOCK PICKS
		10, 1, 0, 1, 1,
		// MAGNIFIER - ZOKATHRA SPELL - BONES
		2, 0, 8
	};

	if (thing == Thing::_none)
		return 0;
	switch (thing.getType()) {
	case k5_WeaponThingType:
		return g238_WeaponInfo[Weapon(f156_getThingData(thing)).getType()]._weight;
	case k6_ArmourThingType:
		return g239_ArmourInfo[Armour(f156_getThingData(thing)).getType()]._weight;
	case k10_JunkThingType: {
		Junk junk(f156_getThingData(thing));
		uint16 weight = g241_junkInfo[junk.getType()];
		if (junk.getType() == k1_JunkTypeWaterskin)
			weight += junk.getChargeCount() * 2;
		return weight;
	}
	case k9_ContainerThingType: {
		uint16 weight = 50;
		Container container(f156_getThingData(thing));
		Thing slotThing = container.getSlot();
		while (slotThing != Thing::_endOfList) {
			weight += f140_getObjectWeight(slotThing);
			slotThing = f159_getNextThing(slotThing);
		}
		return weight;
	}
	case k8_PotionThingType:
		if (Junk(f156_getThingData(thing)).getType() == k20_PotionTypeEmptyFlask) {
			return 1;
		} else {
			return 3;
		}
	case k7_ScrollThingType:
		return 1;
	default:
		break;
	}

	assert(false); // this should never be taken
	return 0; // dummy
}


int16 DungeonMan::f141_getObjectInfoIndex(Thing thing) {
	uint16 *rawType = f156_getThingData(thing);
	switch (thing.getType()) {
	case k7_ScrollThingType:
		return k0_ObjectInfoIndexFirstScroll;
	case k9_ContainerThingType:
		return k1_ObjectInfoIndexFirstContainer + Container(rawType).getType();
	case k10_JunkThingType:
		return k127_ObjectInfoIndexFirstJunk + Junk(rawType).getType();
	case k5_WeaponThingType:
		return k23_ObjectInfoIndexFirstWeapon + Weapon(rawType).getType();
	case k6_ArmourThingType:
		return k69_ObjectInfoIndexFirstArmour + Armour(rawType).getType();
	case k8_PotionThingType:
		return k2_ObjectInfoIndexFirstPotion + Potion(rawType).getType();
	default:
		return -1;
	}
}

void DungeonMan::f163_linkThingToList(Thing thingToLink, Thing thingInList, int16 mapX, int16 mapY) {
	if (thingToLink == Thing::_endOfList)
		return;

	uint16 *rawObjPtr = f156_getThingData(thingToLink);
	*rawObjPtr = Thing::_endOfList.toUint16();

	if (mapX >= 0) {
		Square *squarePtr = (Square*)&_g271_currMapData[mapX][mapY];
		if (squarePtr->get(k0x0010_ThingListPresent)) {
			thingInList = f161_getSquareFirstThing(mapX, mapY);
		} else {
			squarePtr->set(k0x0010_ThingListPresent);
			uint16 *cumulativeCount = &_g270_currMapColCumulativeSquareFirstThingCount[mapX + 1];
			uint16 column = _g282_dungeonColumCount - (_g281_dungeonMapsFirstColumnIndex[_g272_currMapIndex] + mapX) - 1;
			while (column--) {
				(*cumulativeCount++)++;
			}
			uint16 mapYStep = 0;
			squarePtr -= mapY;
			uint16 squareFirstThingIndex = _g270_currMapColCumulativeSquareFirstThingCount[mapX];
			while (mapYStep++ != mapY) {
				if (squarePtr->get(k0x0010_ThingListPresent)) {
					squareFirstThingIndex++;
				}
				squarePtr++;
			}
			Thing* thingPtr = &_g283_squareFirstThings[squareFirstThingIndex];
			memmove(thingPtr + 1, thingPtr, sizeof(Thing) * (_g278_dungeonFileHeader._squareFirstThingCount - squareFirstThingIndex - 1));
			*thingPtr = thingToLink;
			return;
		}
	}

	Thing thing = f159_getNextThing(thingInList);
	while (thing != Thing::_endOfList) {
		thing = f159_getNextThing(thing);
		thingInList = thing;
	}
	rawObjPtr = f156_getThingData(thingInList);
	*rawObjPtr = thingToLink.toUint16();
}

WeaponInfo* DungeonMan::f158_getWeaponInfo(Thing thing) {
	Weapon* weapon = (Weapon*)f156_getThingData(thing);
	return &g238_WeaponInfo[weapon->getType()];
}

int16 DungeonMan::f142_getProjectileAspect(Thing thing) {
	ThingType thingType;
	int16 projAspOrd;
	WeaponInfo *weaponInfo;

	if ((thingType = thing.getType()) == k15_ExplosionThingType) {
		if (thing == Thing::_explFireBall)
			return -_vm->M0_indexToOrdinal(k10_ProjectileAspectExplosionFireBall);
		if (thing == Thing::_explSlime)
			return -_vm->M0_indexToOrdinal(k12_ProjectileAspectExplosionSlime);
		if (thing == Thing::_explLightningBolt)
			return -_vm->M0_indexToOrdinal(k3_ProjectileAspectExplosionLightningBolt);
		if ((thing == Thing::_explPoisonBolt) || (thing == Thing::_explPoisonCloud))
			return -_vm->M0_indexToOrdinal(k13_ProjectileAspectExplosionPoisonBoltCloud);

		return -_vm->M0_indexToOrdinal(k11_ProjectileAspectExplosionDefault);
	} else if (thingType == k5_WeaponThingType) {
		weaponInfo = f158_getWeaponInfo(thing);
		if (projAspOrd = weaponInfo->getProjectileAspectOrdinal())
			return -projAspOrd;
	}

	return g237_ObjectInfo[f141_getObjectInfoIndex(thing)]._objectAspectIndex;
}

}