scummvm/engines/dm/dungeonman.cpp

1329 lines
57 KiB
C++
Raw Normal View History

2016-08-26 22:36:31 +02:00
/* 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"
2016-06-15 22:42:08 +02:00
#include "dungeonman.h"
#include "timeline.h"
namespace DM {
2016-08-26 22:43:17 +02:00
ObjectInfo g237_ObjectInfo[180] = { // @ G0237_as_Graphic559_ObjectInfo
2016-06-19 00:29:56 +02:00
/* { 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 */
2016-08-26 22:43:17 +02:00
ArmourInfo g239_ArmourInfo[58] = { // G0239_as_Graphic559_ArmourInfo
2016-06-18 12:58:34 +02:00
/* { 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 */
2016-08-26 22:43:17 +02:00
WeaponInfo g238_WeaponInfo[46] = { // @ G0238_as_Graphic559_WeaponInfo
2016-06-18 12:44:41 +02:00
/* { 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 */
2016-05-22 00:32:53 +02:00
2016-08-26 22:43:17 +02:00
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::mapCoordsAfterRelMovement(direction dir, int16 stepsForward, int16 stepsRight, int16 &posX, int16 &posY) {
2016-06-29 22:51:40 +02:00
posX += _vm->_dirIntoStepCountEast[dir] * stepsForward;
posY += _vm->_dirIntoStepCountNorth[dir] * stepsForward;
turnDirRight(dir);
2016-06-29 22:51:40 +02:00
posX += _vm->_dirIntoStepCountEast[dir] * stepsRight;
posY += _vm->_dirIntoStepCountNorth[dir] * stepsRight;
}
2016-07-02 13:47:19 +02:00
DungeonMan::DungeonMan(DMEngine *dmEngine) : _vm(dmEngine), _rawDunFileData(NULL), _g277_dungeonMaps(NULL), _g276_dungeonRawMapData(NULL) {
_g282_dungeonColumCount = 0;
2016-07-02 13:47:19 +02:00
_g281_dungeonMapsFirstColumnIndex = nullptr;
_g280_dungeonColumnsCumulativeSquareThingCount = nullptr;
_g283_squareFirstThings = nullptr;
_g260_dungeonTextData = nullptr;
_g279_dungeonMapData = nullptr;
for (int i = 0; i < 16; i++)
2016-07-02 13:47:19 +02:00
_g284_thingData[i] = nullptr;
2016-07-02 13:47:19 +02:00
_g308_partyDir = kDirNorth;
_g306_partyMapX = 0;
_g307_partyMapY = 0;
_g309_partyMapIndex = 0;
_g272_currMapIndex = 0;
_g273_currMapWidth = 0;
_g274_currMapHeight = 0;
2016-07-02 13:47:19 +02:00
_g271_currMapData = nullptr;
_g269_currMap = nullptr;
_g270_currMapColCumulativeSquareFirstThingCount = nullptr;
2016-07-02 13:47:19 +02:00
_vm->_g298_newGame = true;
_vm->_g523_restartGameRequest = false;
_rawDunFileDataSize = 0;
_rawDunFileData = nullptr;
2016-07-02 13:47:19 +02:00
_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++)
2016-07-02 13:47:19 +02:00
_g278_dungeonFileHeader._thingCounts[i] = 0;
2016-07-02 13:47:19 +02:00
_g277_dungeonMaps = nullptr;
_g276_dungeonRawMapData = nullptr;
2016-08-26 22:43:17 +02:00
_g265_currMapInscriptionWallOrnIndex = 0;
_g286_isFacingAlcove = false;
_g287_isFacingViAltar = false;
_g288_isFacingFountain = false;
for (int j = 0; j < 6; j++)
2016-08-26 22:43:17 +02:00
_g291_dungeonViewClickableBoxes[j].setToZero();
}
2016-05-04 11:23:52 +02:00
DungeonMan::~DungeonMan() {
delete[] _rawDunFileData;
2016-07-02 13:47:19 +02:00
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) {
2016-07-02 13:47:19 +02:00
if (_g284_thingData[i])
delete[] _g284_thingData[i][0];
delete[] _g284_thingData[i];
}
2016-05-04 11:23:52 +02:00
}
void DungeonMan::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();
}
2016-07-02 02:58:44 +02:00
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 */
2016-07-02 02:58:44 +02:00
};
// this is the number of uint16s the data has to be stored, not the length of the data in dungeon.dat!
2016-07-02 02:58:44 +02:00
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 */
2016-07-02 02:58:44 +02:00
};
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::loadDungeonFile() {
2016-07-02 13:47:19 +02:00
if (_vm->_g298_newGame)
decompressDungeonFile();
Common::MemoryReadStream dunDataStream(_rawDunFileData, _rawDunFileDataSize, DisposeAfterUse::NO);
2016-07-02 13:47:19 +02:00
// 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
2016-07-02 13:47:19 +02:00
_g278_dungeonFileHeader._textDataWordCount = dunDataStream.readUint16BE();
uint16 partyPosition = dunDataStream.readUint16BE();
2016-07-02 13:47:19 +02:00
_g278_dungeonFileHeader._partyStartDir = (direction)((partyPosition >> 10) & 3);
_g278_dungeonFileHeader._partyStartPosY = (partyPosition >> 5) & 0x1F;
_g278_dungeonFileHeader._partyStartPosX = (partyPosition >> 0) & 0x1F;
_g278_dungeonFileHeader._squareFirstThingCount = dunDataStream.readUint16BE();
2016-08-26 22:43:17 +02:00
for (uint16 i = 0; i < k16_ThingTypeTotal; ++i)
2016-07-02 13:47:19 +02:00
_g278_dungeonFileHeader._thingCounts[i] = dunDataStream.readUint16BE();
// init party position and mapindex
2016-07-02 13:47:19 +02:00
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
2016-07-02 13:47:19 +02:00
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
2016-07-02 13:47:19 +02:00
_g277_dungeonMaps[i]._offsetMapX = dunDataStream.readByte();
_g277_dungeonMaps[i]._offsetMapY = dunDataStream.readByte();
uint16 tmp = dunDataStream.readUint16BE();
2016-07-02 13:47:19 +02:00
_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();
2016-07-02 13:47:19 +02:00
_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();
2016-07-02 13:47:19 +02:00
_g277_dungeonMaps[i]._difficulty = tmp >> 12;
_g277_dungeonMaps[i]._creatureTypeCount = (tmp >> 4) & 0xF;
_g277_dungeonMaps[i]._doorOrnCount = tmp & 0xF;
tmp = dunDataStream.readUint16BE();
2016-07-02 13:47:19 +02:00
_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
2016-07-02 13:47:19 +02:00
delete[] _g281_dungeonMapsFirstColumnIndex;
_g281_dungeonMapsFirstColumnIndex = new uint16[_g278_dungeonFileHeader._mapCount];
uint16 columCount = 0;
2016-07-02 13:47:19 +02:00
for (uint16 i = 0; i < _g278_dungeonFileHeader._mapCount; ++i) {
_g281_dungeonMapsFirstColumnIndex[i] = columCount;
columCount += _g277_dungeonMaps[i]._width + 1;
}
2016-07-02 13:47:19 +02:00
_g282_dungeonColumCount = columCount;
// TODO: ??? is this - end
2016-05-16 13:37:52 +02:00
2016-07-02 13:47:19 +02:00
uint32 actualSquareFirstThingCount = _g278_dungeonFileHeader._squareFirstThingCount;
if (_vm->_g298_newGame) // TODO: what purpose does this serve?
_g278_dungeonFileHeader._squareFirstThingCount += 300;
// TODO: ??? is this - begin
2016-07-02 13:47:19 +02:00
delete[] _g280_dungeonColumnsCumulativeSquareThingCount;
_g280_dungeonColumnsCumulativeSquareThingCount = new uint16[columCount];
for (uint16 i = 0; i < columCount; ++i)
2016-07-02 13:47:19 +02:00
_g280_dungeonColumnsCumulativeSquareThingCount[i] = dunDataStream.readUint16BE();
// TODO: ??? is this - end
// TODO: ??? is this - begin
2016-07-02 13:47:19 +02:00
delete[] _g283_squareFirstThings;
_g283_squareFirstThings = new Thing[_g278_dungeonFileHeader._squareFirstThingCount];
2016-05-16 13:37:52 +02:00
for (uint16 i = 0; i < actualSquareFirstThingCount; ++i)
2016-07-02 13:47:19 +02:00
_g283_squareFirstThings[i].set(dunDataStream.readUint16BE());
if (_vm->_g298_newGame)
for (uint16 i = 0; i < 300; ++i)
2016-07-02 13:47:19 +02:00
_g283_squareFirstThings[actualSquareFirstThingCount + i] = Thing::_none;
// TODO: ??? is this - end
// load text data
2016-07-02 13:47:19 +02:00
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
2016-07-02 13:47:19 +02:00
if (_vm->_g298_newGame)
_vm->_timeline->_g369_eventMaxCount = 100;
// load things
2016-08-26 22:43:17 +02:00
for (uint16 thingType = k0_DoorThingType; thingType < k16_ThingTypeTotal; ++thingType) {
2016-07-02 13:47:19 +02:00
uint16 thingCount = _g278_dungeonFileHeader._thingCounts[thingType];
if (_vm->_g298_newGame) {
_g278_dungeonFileHeader._thingCounts[thingType] = MIN((thingType == k15_ExplosionThingType) ? 768 : 1024, thingCount + g236_AdditionalThingCounts[thingType]);
}
2016-07-02 02:58:44 +02:00
uint16 thingStoreWordCount = g235_ThingDataWordCount[thingType];
2016-05-16 13:37:52 +02:00
if (thingStoreWordCount == 0)
continue;
2016-07-02 13:47:19 +02:00
if (_g284_thingData[thingType]) {
delete[] _g284_thingData[thingType][0];
delete[] _g284_thingData[thingType];
}
2016-07-02 13:47:19 +02:00
_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;
2016-08-26 22:43:17 +02:00
if (thingType == k4_GroupThingType) {
for (uint16 i = 0; i < thingCount; ++i)
for (uint16 j = 0; j < thingStoreWordCount; ++j) {
if (j == 2 || j == 3)
2016-07-02 13:47:19 +02:00
_g284_thingData[thingType][i][j] = dunDataStream.readByte();
else
2016-07-02 13:47:19 +02:00
_g284_thingData[thingType][i][j] = dunDataStream.readUint16BE();
}
2016-08-26 22:43:17 +02:00
} else if (thingType == k14_ProjectileThingType) {
for (uint16 i = 0; i < thingCount; ++i) {
2016-07-02 13:47:19 +02:00
_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)
2016-07-02 13:47:19 +02:00
_g284_thingData[thingType][i][j] = dunDataStream.readUint16BE();
}
}
2016-05-16 13:37:52 +02:00
2016-07-02 13:47:19 +02:00
if (_vm->_g298_newGame) {
2016-08-26 22:43:17 +02:00
if ((thingType == k4_GroupThingType) || thingType >= k14_ProjectileThingType)
2016-07-02 13:47:19 +02:00
_vm->_timeline->_g369_eventMaxCount += _g278_dungeonFileHeader._thingCounts[thingType];
2016-07-02 02:58:44 +02:00
for (uint16 i = 0; i < g236_AdditionalThingCounts[thingType]; ++i) {
2016-07-02 13:47:19 +02:00
_g284_thingData[thingType][thingCount + i][0] = Thing::_none.toUint16();
2016-05-16 13:37:52 +02:00
}
}
}
// load map data
2016-07-02 13:47:19 +02:00
if (!_vm->_g523_restartGameRequest)
_g276_dungeonRawMapData = _rawDunFileData + dunDataStream.pos();
2016-07-02 13:47:19 +02:00
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) {
2016-07-02 13:47:19 +02:00
_g279_dungeonMapData[i] = colFirstSquares;
byte *square = _g276_dungeonRawMapData + _g277_dungeonMaps[i]._rawDunDataOffset;
*colFirstSquares++ = square;
2016-07-02 13:47:19 +02:00
for (uint16 w = 1; w <= _g277_dungeonMaps[i]._width; ++w) {
square += _g277_dungeonMaps[i]._height + 1;
*colFirstSquares++ = square;
}
}
}
}
void DungeonMan::setCurrentMap(uint16 mapIndex) {
2016-07-02 13:47:19 +02:00
_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]];
2016-05-07 22:48:19 +02:00
}
void DungeonMan::setCurrentMapAndPartyMap(uint16 mapIndex) {
setCurrentMap(mapIndex);
2016-07-02 13:47:19 +02:00
byte *metaMapData = _g271_currMapData[_g273_currMapWidth - 1] + _g274_currMapHeight;
2016-07-02 00:27:05 +02:00
_vm->_displayMan->_g264_currMapAllowedCreatureTypes = metaMapData;
2016-07-02 13:47:19 +02:00
metaMapData += _g269_currMap->_creatureTypeCount;
memcpy(_vm->_displayMan->_g261_currMapWallOrnIndices, metaMapData, _g269_currMap->_wallOrnCount);
2016-07-02 13:47:19 +02:00
metaMapData += _g269_currMap->_wallOrnCount;
memcpy(_vm->_displayMan->_g262_currMapFloorOrnIndices, metaMapData, _g269_currMap->_floorOrnCount);
2016-07-02 13:47:19 +02:00
metaMapData += _g269_currMap->_wallOrnCount;
memcpy(_vm->_displayMan->_g263_currMapDoorOrnIndices, metaMapData, _g269_currMap->_doorOrnCount);
2016-07-02 13:47:19 +02:00
_g265_currMapInscriptionWallOrnIndex = _g269_currMap->_wallOrnCount;
2016-08-26 22:43:17 +02:00
_vm->_displayMan->_g261_currMapWallOrnIndices[_g265_currMapInscriptionWallOrnIndex] = k0_WallOrnInscription;
}
Square DungeonMan::getSquare(int16 mapX, int16 mapY) {
2016-07-02 13:47:19 +02:00
bool isInXBounds = (mapX >= 0) && (mapX < _g273_currMapWidth);
bool isInYBounds = (mapY >= 0) && (mapY < _g274_currMapHeight);
2016-05-07 22:48:19 +02:00
if (isInXBounds && isInYBounds)
2016-07-02 13:47:19 +02:00
return Square(_g271_currMapData[mapX][mapY]);
Square tmpSquare;
if (isInYBounds) {
2016-07-02 13:47:19 +02:00
tmpSquare.set(_g271_currMapData[0][mapY]);
2016-08-26 22:43:17 +02:00
if (mapX == -1 && (tmpSquare.getType() == k1_CorridorElemType || tmpSquare.getType() == k2_PitElemType))
return Square(k0_WallElemType).set(k0x0004_WallEastRandOrnAllowed);
2016-07-02 13:47:19 +02:00
tmpSquare.set(_g271_currMapData[_g273_currMapWidth - 1][mapY]);
if (mapX == _g273_currMapWidth && (tmpSquare.getType() == k1_CorridorElemType || tmpSquare.getType() == k2_PitElemType))
2016-08-26 22:43:17 +02:00
return Square(k0_WallElemType).set(k0x0001_WallWestRandOrnAllowed);
} else if (isInXBounds) {
2016-07-02 13:47:19 +02:00
tmpSquare.set(_g271_currMapData[mapX][0]);
2016-08-26 22:43:17 +02:00
if (mapY == -1 && (tmpSquare.getType() == k1_CorridorElemType || tmpSquare.getType() == k2_PitElemType))
return Square(k0_WallElemType).set(k0x0002_WallSouthRandOrnAllowed);
2016-07-02 13:47:19 +02:00
tmpSquare.set(_g271_currMapData[mapX][_g274_currMapHeight - 1]);
if (mapY == _g274_currMapHeight && (tmpSquare.getType() == k1_CorridorElemType || tmpSquare.getType() == k2_PitElemType))
2016-08-26 22:43:17 +02:00
return Square((k0_WallElemType << 5) | k0x0008_WallNorthRandOrnAllowed);
}
2016-08-26 22:43:17 +02:00
return Square(k0_WallElemType);
2016-05-07 22:48:19 +02:00
}
Square DungeonMan::getRelSquare(direction dir, int16 stepsForward, int16 stepsRight, int16 posX, int16 posY) {
2016-05-07 22:48:19 +02:00
mapCoordsAfterRelMovement(dir, stepsForward, stepsForward, posX, posY);
return getSquare(posX, posY);
}
int16 DungeonMan::getSquareFirstThingIndex(int16 mapX, int16 mapY) {
2016-07-02 13:47:19 +02:00
if (mapX < 0 || mapX >= _g273_currMapWidth || mapY < 0 || mapY >= _g274_currMapHeight || !Square(_g271_currMapData[mapX][mapY]).get(k0x0010_ThingListPresent))
return -1;
2016-05-15 18:59:55 +02:00
int16 y = 0;
2016-07-02 13:47:19 +02:00
uint16 index = _g270_currMapColCumulativeSquareFirstThingCount[mapX];
byte* square = _g271_currMapData[mapX];
while (y++ != mapY)
2016-08-26 22:43:17 +02:00
if (Square(*square++).get(k0x0010_ThingListPresent))
index++;
return index;
}
Thing DungeonMan::getSquareFirstThing(int16 mapX, int16 mapY) {
int16 index = getSquareFirstThingIndex(mapX, mapY);
if (index == -1)
return Thing::_endOfList;
2016-07-02 13:47:19 +02:00
return _g283_squareFirstThings[index];
}
2016-05-21 12:55:37 +02:00
// TODO: get rid of the GOTOs
void DungeonMan::setSquareAspect(uint16 *aspectArray, direction dir, int16 mapX, int16 mapY) { // complete, except where marked
2016-07-02 00:27:05 +02:00
_vm->_displayMan->_g289_championPortraitOrdinal = 0; // BUG0_75, possible fix
2016-05-21 12:55:37 +02:00
for (uint16 i = 0; i < 5; ++i)
aspectArray[i] = 0;
Thing thing = getSquareFirstThing(mapX, mapY);
Square square = getSquare(mapX, mapY);
2016-08-26 22:43:17 +02:00
aspectArray[k0_ElemAspect] = square.getType();
2016-06-04 10:11:25 +02:00
bool leftOrnAllowed = false;
bool rightOrnAllowed = false;
bool frontOrnAllowed = false;
bool squareIsFakeWall = false;
bool footPrintsAllowed = false;
switch (square.getType()) {
2016-08-26 22:43:17 +02:00
case k0_WallElemType:
switch (dir) {
case kDirNorth:
2016-08-26 22:43:17 +02:00
leftOrnAllowed = square.get(k0x0004_WallEastRandOrnAllowed);
frontOrnAllowed = square.get(k0x0002_WallSouthRandOrnAllowed);
rightOrnAllowed = square.get(k0x0001_WallWestRandOrnAllowed);
break;
case kDirEast:
2016-08-26 22:43:17 +02:00
leftOrnAllowed = square.get(k0x0002_WallSouthRandOrnAllowed);
frontOrnAllowed = square.get(k0x0001_WallWestRandOrnAllowed);
rightOrnAllowed = square.get(k0x0008_WallNorthRandOrnAllowed);
break;
case kDirSouth:
2016-08-26 22:43:17 +02:00
leftOrnAllowed = square.get(k0x0001_WallWestRandOrnAllowed);
frontOrnAllowed = square.get(k0x0008_WallNorthRandOrnAllowed);
rightOrnAllowed = square.get(k0x0004_WallEastRandOrnAllowed);
break;
case kDirWest:
2016-08-26 22:43:17 +02:00
leftOrnAllowed = square.get(k0x0008_WallNorthRandOrnAllowed);
frontOrnAllowed = square.get(k0x0004_WallEastRandOrnAllowed);
rightOrnAllowed = square.get(k0x0002_WallSouthRandOrnAllowed);
break;
2016-06-23 23:22:50 +02:00
default:
break;
}
2016-05-21 12:55:37 +02:00
T0172010_ClosedFakeWall:
setSquareAspectOrnOrdinals(aspectArray, leftOrnAllowed, frontOrnAllowed, rightOrnAllowed, dir, mapX, mapY, squareIsFakeWall);
2016-08-26 22:43:17 +02:00
while ((thing != Thing::_endOfList) && (thing.getType() <= k3_SensorThingType)) {
int16 sideIndex = (thing.getCell() - dir) & 3;
if (sideIndex) {
2016-08-26 22:43:17 +02:00
if (thing.getType() == k2_TextstringType) {
if (TextString(getThingData(thing)).isVisible()) {
2016-08-26 22:43:17 +02:00
aspectArray[sideIndex + 1] = _g265_currMapInscriptionWallOrnIndex + 1;
2016-07-02 00:27:05 +02:00
_vm->_displayMan->_g290_inscriptionThing = thing; // BUG0_76
2016-05-21 12:55:37 +02:00
}
} else {
Sensor sensor(getThingData(thing));
aspectArray[sideIndex + 1] = sensor.getOrnOrdinal();
2016-08-26 22:43:17 +02:00
if (sensor.getType() == k127_SensorWallChampionPortrait) {
2016-07-02 00:27:05 +02:00
_vm->_displayMan->_g289_championPortraitOrdinal = _vm->indexToOrdinal(sensor.getData());
}
}
}
thing = getNextThing(thing);
}
2016-07-02 13:47:19 +02:00
if (squareIsFakeWall && (_g306_partyMapX != mapX) && (_g307_partyMapY != mapY)) {
2016-08-26 22:43:17 +02:00
aspectArray[k1_FirstGroupOrObjectAspect] = Thing::_endOfList.toUint16();
2016-05-21 12:55:37 +02:00
return;
}
break;
2016-08-26 22:43:17 +02:00
case k2_PitElemType:
if (square.get(k0x0008_PitOpen)) {
aspectArray[k2_PitInvisibleAspect] = square.get(k0x0004_PitInvisible);
footPrintsAllowed = square.toByte() & 1;
} else {
2016-08-26 22:43:17 +02:00
aspectArray[k0_ElemAspect] = k1_CorridorElemType;
footPrintsAllowed = true;
}
2016-05-21 12:55:37 +02:00
goto T0172030_Pit;
2016-08-26 22:43:17 +02:00
case k6_FakeWallElemType:
if (!square.get(k0x0004_FakeWallOpen)) {
aspectArray[k0_ElemAspect] = k0_WallElemType;
leftOrnAllowed = rightOrnAllowed = frontOrnAllowed = square.get(k0x0008_FakeWallRandOrnOrFootPAllowed);
2016-05-21 12:55:37 +02:00
squareIsFakeWall = true;
goto T0172010_ClosedFakeWall;
}
2016-08-26 22:43:17 +02:00
aspectArray[k0_WallElemType] = k1_CorridorElemType;
footPrintsAllowed = square.get(k0x0008_FakeWallRandOrnOrFootPAllowed);
square = Square(footPrintsAllowed ? 8 : 0);
2016-05-21 12:55:37 +02:00
// intentional fallthrough
2016-08-26 22:43:17 +02:00
case k1_CorridorElemType:
2016-07-02 13:47:19 +02:00
aspectArray[k4_FloorOrnOrdAspect] = getRandomOrnOrdinal(square.get(k0x0008_CorridorRandOrnAllowed), _g269_currMap->_randFloorOrnCount, mapX, mapY, 30);
2016-05-21 12:55:37 +02:00
T0172029_Teleporter:
footPrintsAllowed = true;
T0172030_Pit:
2016-08-26 22:43:17 +02:00
while ((thing != Thing::_endOfList) && (thing.getType() <= k3_SensorThingType)) {
if (thing.getType() == k3_SensorThingType)
aspectArray[k4_FloorOrnOrdAspect] = Sensor(getThingData(thing)).getOrnOrdinal();
2016-05-21 12:55:37 +02:00
thing = getNextThing(thing);
}
goto T0172049_Footprints;
2016-08-26 22:43:17 +02:00
case k5_TeleporterElemType:
aspectArray[k2_TeleporterVisibleAspect] = square.get(k0x0008_TeleporterOpen) && square.get(k0x0004_TeleporterVisible);
2016-05-21 12:55:37 +02:00
goto T0172029_Teleporter;
2016-08-26 22:43:17 +02:00
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);
2016-05-21 12:55:37 +02:00
footPrintsAllowed = false;
goto T0172046_Stairs;
2016-08-26 22:43:17 +02:00
case k4_DoorElemType:
if ((square.get(k0x0008_DoorNorthSouthOrient) >> 3) == (isOrientedWestEast(dir) ? 1 : 0)) {
aspectArray[k0_ElemAspect] = k16_DoorSideElemType;
2016-05-21 12:55:37 +02:00
} else {
2016-08-26 22:43:17 +02:00
aspectArray[k0_ElemAspect] = k17_DoorFrontElemType;
aspectArray[k2_DoorStateAspect] = square.getDoorState();
aspectArray[k3_DoorThingIndexAspect] = getSquareFirstThing(mapX, mapY).getIndex();
2016-05-21 12:55:37 +02:00
}
footPrintsAllowed = true;
T0172046_Stairs:
2016-08-26 22:43:17 +02:00
while ((thing != Thing::_endOfList) && (thing.getType() <= k3_SensorThingType))
2016-05-21 12:55:37 +02:00
thing = getNextThing(thing);
T0172049_Footprints:
unsigned char scentOrdinal; // see next line comment
2016-05-21 12:55:37 +02:00
if (footPrintsAllowed) // TODO: I skipped some party query code, must come back later and complete
2016-08-26 22:43:17 +02:00
aspectArray[k4_FloorOrnOrdAspect] &= k0x8000_FootprintsAspect;
2016-06-23 23:22:50 +02:00
break;
default:
break;
}
2016-08-26 22:43:17 +02:00
aspectArray[k1_FirstGroupOrObjectAspect] = thing.toUint16();
}
void DungeonMan::setSquareAspectOrnOrdinals(uint16 *aspectArray, bool leftAllowed, bool frontAllowed, bool rightAllowed, direction dir,
int16 mapX, int16 mapY, bool isFakeWall) {
2016-07-02 13:47:19 +02:00
int16 ornCount = _g269_currMap->_randWallOrnCount;
turnDirRight(dir);
2016-08-26 22:43:17 +02:00
aspectArray[k2_RightWallOrnOrdAspect] = getRandomOrnOrdinal(leftAllowed, ornCount, mapX, ++mapY * (dir + 1), 30);
turnDirRight(dir);
2016-08-26 22:43:17 +02:00
aspectArray[k3_FrontWallOrnOrdAspect] = getRandomOrnOrdinal(frontAllowed, ornCount, mapX, ++mapY * (dir + 1), 30);
turnDirRight(dir);
2016-08-26 22:43:17 +02:00
aspectArray[k4_LeftWallOrnOrdAspect] = getRandomOrnOrdinal(rightAllowed, ornCount, mapX, ++mapY * (dir + 1), 30);
2016-07-02 13:47:19 +02:00
if (isFakeWall || mapX < 0 || mapX >= _g273_currMapWidth || mapY < 0 || mapY >= _g274_currMapHeight) {
2016-08-26 22:43:17 +02:00
for (uint16 i = k2_RightWallOrnOrdAspect; i <= k4_LeftWallOrnOrdAspect; ++i) {
2016-06-23 23:12:39 +02:00
if (isWallOrnAnAlcove(_vm->ordinalToIndex(aspectArray[i])))
aspectArray[i] = 0;
}
}
}
int16 DungeonMan::getRandomOrnOrdinal(bool allowed, int16 count, int16 mapX, int16 mapY, int16 modulo) {
int16 index = (((((2000 + (mapX << 5) + mapY) * 31417) >> 1)
2016-07-02 13:47:19 +02:00
+ (3000 + (_g272_currMapIndex << 6) + _g273_currMapWidth + _g274_currMapHeight) * 11
+ _g278_dungeonFileHeader._ornamentRandomSeed) >> 2) % modulo;
if (allowed && index < count)
2016-06-23 23:12:39 +02:00
return _vm->indexToOrdinal(index);
return 0;
}
bool DungeonMan::isWallOrnAnAlcove(int16 wallOrnIndex) {
if (wallOrnIndex >= 0)
2016-07-02 00:27:05 +02:00
for (uint16 i = 0; i < k3_AlcoveOrnCount; ++i)
if (_vm->_displayMan->_g267_currMapAlcoveOrnIndices[i] == wallOrnIndex)
return true;
return false;
}
uint16 *DungeonMan::getThingData(Thing thing) {
2016-07-02 13:47:19 +02:00
return _g284_thingData[thing.getType()][thing.getIndex()];
}
uint16* DungeonMan::getSquareFirstThingData(int16 mapX, int16 mapY) {
return getThingData(getSquareFirstThing(mapX, mapY));
}
Thing DungeonMan::getNextThing(Thing thing) {
return getThingData(thing)[0]; // :)
}
2016-07-02 02:58:44 +02:00
char g255_MessageAndScrollEscReplacementStrings[32][8] = { // @ G0255_aac_Graphic559_MessageAndScrollEscapeReplacementStrings
2016-05-22 17:18:56 +02:00
{'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}};
2016-07-02 02:58:44 +02:00
char g256_EscReplacementCharacters[32][2] = { // @ G0256_aac_Graphic559_EscapeReplacementCharacters
2016-05-22 17:18:56 +02:00
{'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}};
2016-07-02 02:58:44 +02:00
char g257_InscriptionEscReplacementStrings[32][8] = { // @ G0257_aac_Graphic559_InscriptionEscapeReplacementStrings
2016-05-22 17:18:56 +02:00
{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}};
2016-05-22 18:43:35 +02:00
void DungeonMan::decodeText(char *destString, Thing thing, TextType type) {
char sepChar;
2016-07-02 13:47:19 +02:00
TextString textString(_g284_thingData[k2_TextstringType][thing.getIndex()]);
2016-08-26 22:43:17 +02:00
if ((textString.isVisible()) || (type & k0x8000_DecodeEvenIfInvisible)) {
type = (TextType)(type & ~k0x8000_DecodeEvenIfInvisible);
if (type == k1_TextTypeMessage) {
2016-05-22 18:43:35 +02:00
*destString++ = '\n';
sepChar = ' ';
2016-08-26 22:43:17 +02:00
} else if (type == k0_TextTypeInscription) {
2016-06-17 23:08:04 +02:00
sepChar = (char)0x80;
2016-05-22 18:43:35 +02:00
} else {
sepChar = '\n';
}
uint16 codeCounter = 0;
int16 escChar = 0;
2016-07-02 13:47:19 +02:00
uint16 *codeWord = _g260_dungeonTextData + textString.getWordOffset();
2016-06-04 10:11:25 +02:00
uint16 code = 0, codes = 0;
char *escReplString = nullptr;
2016-05-22 18:43:35 +02:00
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) {
2016-08-26 22:43:17 +02:00
if (type != k0_TextTypeInscription) {
2016-07-02 02:58:44 +02:00
escReplString = g255_MessageAndScrollEscReplacementStrings[code];
2016-05-22 18:43:35 +02:00
} else {
2016-07-02 02:58:44 +02:00
escReplString = g257_InscriptionEscReplacementStrings[code];
2016-05-22 18:43:35 +02:00
}
} else {
2016-07-02 02:58:44 +02:00
escReplString = g256_EscReplacementCharacters[code];
2016-05-22 18:43:35 +02:00
}
strcat(destString, escReplString);
destString += strlen(escReplString);
escChar = 0;
} else if (code < 28) {
2016-08-26 22:43:17 +02:00
if (type != k0_TextTypeInscription) {
2016-05-22 18:43:35 +02:00
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;
}
}
}
2016-08-26 22:43:17 +02:00
*destString = ((type == k0_TextTypeInscription) ? 0x81 : '\0');
2016-05-22 17:18:56 +02:00
}
uint16 DungeonMan::getObjectWeight(Thing thing) {
2016-07-02 02:58:44 +02:00
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()) {
2016-08-26 22:43:17 +02:00
case k5_WeaponThingType:
return g238_WeaponInfo[Weapon(getThingData(thing)).getType()]._weight;
case k6_ArmourThingType:
return g239_ArmourInfo[Armour(getThingData(thing)).getType()]._weight;
case k10_JunkThingType: {
Junk junk(getThingData(thing));
2016-07-02 02:58:44 +02:00
uint16 weight = g241_junkInfo[junk.getType()];
2016-08-26 22:43:17 +02:00
if (junk.getType() == k1_JunkTypeWaterskin)
weight += junk.getChargeCount() * 2;
return weight;
}
2016-08-26 22:43:17 +02:00
case k9_ContainerThingType: {
uint16 weight = 50;
Container container(getThingData(thing));
Thing slotThing = container.getSlot();
while (slotThing != Thing::_endOfList) {
weight += getObjectWeight(slotThing);
slotThing = getNextThing(slotThing);
}
return weight;
}
2016-08-26 22:43:17 +02:00
case k8_PotionThingType:
if (Junk(getThingData(thing)).getType() == k20_PotionTypeEmptyFlask) {
return 1;
} else {
return 3;
}
2016-08-26 22:43:17 +02:00
case k7_ScrollThingType:
return 1;
2016-06-23 23:22:50 +02:00
default:
break;
}
assert(false); // this should never be taken
return 0; // dummy
}
int16 DungeonMan::getObjectInfoIndex(Thing thing) {
uint16 *rawType = getThingData(thing);
switch (thing.getType()) {
2016-08-26 22:43:17 +02:00
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;
}
}
2016-06-27 21:46:05 +02:00
void DungeonMan::linkThingToList(Thing thingToLink, Thing thingInList, int16 mapX, int16 mapY) {
if (thingToLink == Thing::_endOfList)
2016-06-27 21:46:05 +02:00
return;
uint16 *rawObjPtr = getThingData(thingToLink);
*rawObjPtr = Thing::_endOfList.toUint16();
2016-06-27 21:46:05 +02:00
if (mapX >= 0) {
2016-07-02 13:47:19 +02:00
Square *squarePtr = (Square*)&_g271_currMapData[mapX][mapY];
2016-08-26 22:43:17 +02:00
if (squarePtr->get(k0x0010_ThingListPresent)) {
2016-06-27 21:46:05 +02:00
thingInList = getSquareFirstThing(mapX, mapY);
} else {
2016-08-26 22:43:17 +02:00
squarePtr->set(k0x0010_ThingListPresent);
2016-07-02 13:47:19 +02:00
uint16 *cumulativeCount = &_g270_currMapColCumulativeSquareFirstThingCount[mapX + 1];
uint16 column = _g282_dungeonColumCount - (_g281_dungeonMapsFirstColumnIndex[_g272_currMapIndex] + mapX) - 1;
2016-06-27 21:46:05 +02:00
while (column--) {
(*cumulativeCount++)++;
}
uint16 mapYStep = 0;
squarePtr -= mapY;
2016-07-02 13:47:19 +02:00
uint16 squareFirstThingIndex = _g270_currMapColCumulativeSquareFirstThingCount[mapX];
2016-06-27 21:46:05 +02:00
while (mapYStep++ != mapY) {
2016-08-26 22:43:17 +02:00
if (squarePtr->get(k0x0010_ThingListPresent)) {
2016-06-27 21:46:05 +02:00
squareFirstThingIndex++;
}
squarePtr++;
}
2016-07-02 13:47:19 +02:00
Thing* thingPtr = &_g283_squareFirstThings[squareFirstThingIndex];
memmove(thingPtr + 1, thingPtr, sizeof(Thing) * (_g278_dungeonFileHeader._squareFirstThingCount - squareFirstThingIndex - 1));
2016-06-27 21:46:05 +02:00
*thingPtr = thingToLink;
return;
}
}
Thing thing = getNextThing(thingInList);
while (thing != Thing::_endOfList) {
2016-06-27 21:46:05 +02:00
thing = getNextThing(thing);
thingInList = thing;
}
rawObjPtr = getThingData(thingInList);
*rawObjPtr = thingToLink.toUint16();
}
WeaponInfo* DungeonMan::getWeaponInfo(Thing thing) {
Weapon* weapon = (Weapon*)getThingData(thing);
2016-08-26 22:43:17 +02:00
return &g238_WeaponInfo[weapon->getType()];
}
int16 DungeonMan::getProjectileAspect(Thing thing) {
ThingType thingType;
int16 projAspOrd;
WeaponInfo *weaponInfo;
2016-08-26 22:43:17 +02:00
if ((thingType = thing.getType()) == k15_ExplosionThingType) {
if (thing == Thing::_explFireBall)
2016-07-02 00:27:05 +02:00
return -_vm->indexToOrdinal(k10_ProjectileAspectExplosionFireBall);
if (thing == Thing::_explSlime)
2016-07-02 00:27:05 +02:00
return -_vm->indexToOrdinal(k12_ProjectileAspectExplosionSlime);
if (thing == Thing::_explLightningBolt)
2016-07-02 00:27:05 +02:00
return -_vm->indexToOrdinal(k3_ProjectileAspectExplosionLightningBolt);
if ((thing == Thing::_explPoisonBolt) || (thing == Thing::_explPoisonCloud))
2016-07-02 00:27:05 +02:00
return -_vm->indexToOrdinal(k13_ProjectileAspectExplosionPoisonBoltCloud);
2016-07-02 00:27:05 +02:00
return -_vm->indexToOrdinal(k11_ProjectileAspectExplosionDefault);
2016-08-26 22:43:17 +02:00
} else if (thingType == k5_WeaponThingType) {
weaponInfo = getWeaponInfo(thing);
if (projAspOrd = weaponInfo->getProjectileAspectOrdinal())
return -projAspOrd;
}
2016-08-26 22:43:17 +02:00
return g237_ObjectInfo[getObjectInfoIndex(thing)]._objectAspectIndex;
}
2016-06-27 21:46:05 +02:00
}