/* 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" #include "champion.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) { _rawDunFileDataSize = 0; _rawDunFileData = nullptr; _g282_dungeonColumCount = 0; _g281_dungeonMapsFirstColumnIndex = nullptr; _g282_dungeonColumCount = 0; _g280_dungeonColumnsCumulativeSquareThingCount = nullptr; _g283_squareFirstThings = nullptr; _g260_dungeonTextData = nullptr; for (uint16 i = 0; i < 16; ++i) _g284_thingData[i] = nullptr; _g279_dungeonMapData = nullptr; _g308_partyDir = (direction)0; _g306_partyMapX = 0; _g307_partyMapY = 0; _g309_partyMapIndex = 0; _g272_currMapIndex = kM1_mapIndexNone; _g271_currMapData = nullptr; _g269_currMap = nullptr; _g273_currMapWidth = 0; _g274_currMapHeight = 0; _g270_currMapColCumulativeSquareFirstThingCount = nullptr; _g277_dungeonMaps = nullptr; _g276_dungeonRawMapData = nullptr; _g265_currMapInscriptionWallOrnIndex = 0; for (uint16 i = 0; i < 6; ++i) _g291_dungeonViewClickableBoxes[i].setToZero(); _g286_isFacingAlcove = false; _g287_isFacingViAltar = false; _g288_isFacingFountain = false; _g285_squareAheadElement = (ElementType)0; for (uint16 i = 0; i < 5; ++i) _g292_pileTopObject[i] = Thing(0); for (uint16 i = 0; i < 2; ++i) _g275_currMapDoorInfo[i].resetToZero(); } 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) { static DoorInfo g254_doorInfo[4] = { // @ G0254_as_Graphic559_DoorInfo /* { Attributes, Defense } */ DoorInfo(3, 110), /* Door type 0 Portcullis */ DoorInfo(0, 42), /* Door type 1 Wooden door */ DoorInfo(0, 230), /* Door type 2 Iron door */ DoorInfo(5, 255)}; /* Door type 3 Ra door */ if (_g272_currMapIndex == mapIndex) return; _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; _g275_currMapDoorInfo[0] = g254_doorInfo[_g269_currMap->_doorSet0]; _g275_currMapDoorInfo[1] = g254_doorInfo[_g269_currMap->_doorSet1]; _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: produce more GOTOs void DungeonMan::f172_setSquareAspect(uint16 *aspectArray, direction dir, int16 mapX, int16 mapY) { // complete, except where marked #define thingType dir byte L0307_uc_Multiple; #define square L0307_uc_Multiple #define footprintsAllowed L0307_uc_Multiple #define scentOrdinal L0307_uc_Multiple Sensor* sensor; bool leftRandWallOrnAllowed; int16 L0310_i_Multiple; #define frontRandWallOrnAllowed L0310_i_Multiple #define sideIndex L0310_i_Multiple bool rightRandWallOrnAllowed; int16 thingTypeRedEagle; bool squreIsFakeWall; Thing thing; for (uint16 i = 0; i < 5; ++i) aspectArray[i] = 0; thing = _vm->_dungeonMan->f161_getSquareFirstThing(mapX, mapY); square = _vm->_dungeonMan->f151_getSquare(mapX, mapY).toByte(); switch (aspectArray[k0_ElemAspect] = Square(square).getType()) { case k0_ElementTypeWall: switch (dir) { case kDirNorth: leftRandWallOrnAllowed = getFlag(square, k0x0004_WallEastRandOrnAllowed); frontRandWallOrnAllowed = getFlag(square, k0x0002_WallSouthRandOrnAllowed); rightRandWallOrnAllowed = getFlag(square, k0x0001_WallWestRandOrnAllowed); break; case kDirEast: leftRandWallOrnAllowed = getFlag(square, k0x0002_WallSouthRandOrnAllowed); frontRandWallOrnAllowed = getFlag(square, k0x0001_WallWestRandOrnAllowed); rightRandWallOrnAllowed = getFlag(square, k0x0008_WallNorthRandOrnAllowed); break; case kDirSouth: leftRandWallOrnAllowed = getFlag(square, k0x0001_WallWestRandOrnAllowed); frontRandWallOrnAllowed = getFlag(square, k0x0008_WallNorthRandOrnAllowed); rightRandWallOrnAllowed = getFlag(square, k0x0004_WallEastRandOrnAllowed); break; case kDirWest: leftRandWallOrnAllowed = getFlag(square, k0x0008_WallNorthRandOrnAllowed); frontRandWallOrnAllowed = getFlag(square, k0x0004_WallEastRandOrnAllowed); rightRandWallOrnAllowed = getFlag(square, k0x0002_WallSouthRandOrnAllowed); } /* BUG0_75 Multiple champion portraits are drawn (one at a time) then the game crashes. This variable is only reset to 0 when at least one square in the dungeon view is a wall. If the party is in front of a wall with a champion portrait and the next time the dungeon view is drawn there is no wall square in the view and the square in front of the party is a fake wall with a random ornament then the same champion portrait will be drawn again because the variable was not reset to 0. Each time _vm->_displayMan->f107_isDrawnWallOrnAnAlcove draws the portrait, _vm->_displayMan->_g289_championPortraitOrdinal is decremented so that the portait is different each time the dungeon view is drawn until the game crashes */ _vm->_displayMan->_g289_championPortraitOrdinal = 0; squreIsFakeWall = false; T0172010_ClosedFakeWall: _vm->_dungeonMan->f171_setSquareAspectOrnOrdinals(aspectArray, leftRandWallOrnAllowed, frontRandWallOrnAllowed, rightRandWallOrnAllowed, dir, mapX, mapY, squreIsFakeWall); while ((thing != Thing::_endOfList) && ((thingTypeRedEagle = thing.getType()) <= k3_SensorThingType)) { if (sideIndex = M21_normalizeModulo4(thing.getCell() - dir)) { /* Invisible on the back wall if 0 */ sensor = (Sensor*)_vm->_dungeonMan->f156_getThingData(thing); if (thingTypeRedEagle == k2_TextstringType) { if (((TextString*)sensor)->isVisible()) { aspectArray[sideIndex + 1] = _vm->_dungeonMan->_g265_currMapInscriptionWallOrnIndex + 1; /* BUG0_76 The same text is drawn on multiple sides of a wall square. The engine stores only a single text to draw on a wall in a global variable. Even if different texts are placed on differents sides of the wall, the same text is drawn on each affected side */ _vm->_displayMan->_g290_inscriptionThing = thing; } } else { aspectArray[sideIndex + 1] = sensor->getOrnOrdinal(); if (sensor->getType() == k127_SensorWallChampionPortrait) { _vm->_displayMan->_g289_championPortraitOrdinal = _vm->M0_indexToOrdinal(sensor->getData()); } } } thing = _vm->_dungeonMan->f159_getNextThing(thing); } if (squreIsFakeWall && (_vm->_dungeonMan->_g306_partyMapX != mapX) && (_vm->_dungeonMan->_g307_partyMapY != mapY)) { aspectArray[k1_FirstGroupOrObjectAspect] = Thing::_endOfList.toUint16(); return; } break; case k2_ElementTypePit: if (getFlag(square, k0x0008_PitOpen)) { aspectArray[k2_PitInvisibleAspect] = getFlag(square, k0x0004_PitInvisible); footprintsAllowed &= 0x0001; } else { aspectArray[k0_ElemAspect] = k1_CorridorElemType; footprintsAllowed = true; } goto T0172030_Pit; case k6_ElementTypeFakeWall: if (!getFlag(square, k0x0004_FakeWallOpen)) { aspectArray[k0_ElemAspect] = k0_ElementTypeWall; leftRandWallOrnAllowed = rightRandWallOrnAllowed = frontRandWallOrnAllowed = getFlag(square, k0x0008_FakeWallRandOrnOrFootPAllowed); squreIsFakeWall = true; goto T0172010_ClosedFakeWall; } aspectArray[k0_ElemAspect] = k1_CorridorElemType; footprintsAllowed = getFlag(square, k0x0008_FakeWallRandOrnOrFootPAllowed) ? 8 : 0; case k1_CorridorElemType: aspectArray[k4_FloorOrnOrdAspect] = _vm->_dungeonMan->f170_getRandomOrnOrdinal(getFlag(square, k0x0008_CorridorRandOrnAllowed), _vm->_dungeonMan->_g269_currMap->_randFloorOrnCount, mapX, mapY, 30); T0172029_Teleporter: footprintsAllowed = true; T0172030_Pit: while ((thing != Thing::_endOfList) && ((thingType = (direction)thing.getType()) <= k3_SensorThingType)) { if (thingType == k3_SensorThingType) { sensor = (Sensor*)_vm->_dungeonMan->f156_getThingData(thing); aspectArray[k4_FloorOrnOrdAspect] = sensor->getOrnOrdinal(); } thing = _vm->_dungeonMan->f159_getNextThing(thing); } goto T0172049_Footprints; case k5_ElementTypeTeleporter: aspectArray[k2_TeleporterVisibleAspect] = getFlag(square, k0x0008_TeleporterOpen) && getFlag(square, k0x0004_TeleporterVisible); goto T0172029_Teleporter; case k3_ElementTypeStairs: aspectArray[k0_ElemAspect] = ((getFlag(square, k0x0008_StairsNorthSouthOrient) >> 3) == (isOrientedWestEast(dir) ? 1 : 0)) ? k18_ElementTypeStairsSide : k19_ElementTypeStaisFront; aspectArray[k2_StairsUpAspect] = getFlag(square, k0x0004_StairsUp); footprintsAllowed = false; goto T0172046_Stairs; case k4_DoorElemType: if ((getFlag(square, k0x0008_DoorNorthSouthOrient) >> 3) == (isOrientedWestEast(dir) ? 1 : 0)) { aspectArray[k0_ElemAspect] = k16_DoorSideElemType; } else { aspectArray[k0_ElemAspect] = k17_DoorFrontElemType; aspectArray[k2_DoorStateAspect] = Square(square).getDoorState(); aspectArray[k3_DoorThingIndexAspect] = _vm->_dungeonMan->f161_getSquareFirstThing(mapX, mapY).getIndex(); } footprintsAllowed = true; T0172046_Stairs: while ((thing != Thing::_endOfList) && (thing.getType() <= k3_SensorThingType)) { thing = _vm->_dungeonMan->f159_getNextThing(thing); } T0172049_Footprints: if (footprintsAllowed && (scentOrdinal = _vm->_championMan->f315_getScentOrdinal(mapX, mapY)) && (--scentOrdinal >= _vm->_championMan->_g407_party._firstScentIndex) && (scentOrdinal < _vm->_championMan->_g407_party._lastScentIndex)) { setFlag(aspectArray[k4_FloorOrnOrdAspect], k0x8000_FootprintsAspect); } } 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; } int16 DungeonMan::f154_getLocationAfterLevelChange(int16 mapIndex, int16 levelDelta, int16* mapX, int16* mapY) { int16 newMapX; int16 newMapY; int16 newLevel; int16 offset; Map* map; int16 targetMapIndex; if (_vm->_dungeonMan->_g309_partyMapIndex == k255_mapIndexEntrance) { return kM1_mapIndexNone; } map = _vm->_dungeonMan->_g277_dungeonMaps + mapIndex; newMapX = map->_offsetMapX + *mapX; newMapY = map->_offsetMapY + *mapY; newLevel = map->_level + levelDelta; map = _vm->_dungeonMan->_g277_dungeonMaps; for (targetMapIndex = 0; targetMapIndex < _vm->_dungeonMan->_g278_dungeonFileHeader._mapCount; targetMapIndex++) { if ((map->_level == newLevel) && (newMapX >= (offset = map->_offsetMapX)) && (newMapX <= (offset + map->_width)) && (newMapY >= (offset = map->_offsetMapY)) && (newMapY <= (offset + map->_height))) { *mapY = newMapY - offset; *mapX = newMapX - map->_offsetMapX; return targetMapIndex; } map++; } return kM1_mapIndexNone; } }