1 /* ScummVM - Graphic Adventure Engine
2 *
3 * ScummVM is the legal property of its developers, whose names
4 * are too numerous to list here. Please refer to the COPYRIGHT
5 * file distributed with this source distribution.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 *
21 */
22 
23 /*
24 * Based on the Reverse Engineering work of Christophe Fontanel,
25 * maintainer of the Dungeon Master Encyclopaedia (http://dmweb.free.fr/)
26 */
27 
28 #include "engines/util.h"
29 #include "common/system.h"
30 #include "common/file.h"
31 #include "common/endian.h"
32 #include "graphics/palette.h"
33 
34 #include "dm/gfx.h"
35 #include "dm/dungeonman.h"
36 #include "dm/group.h"
37 #include "dm/timeline.h"
38 #include "dm/champion.h"
39 #include "dm/eventman.h"
40 #include "dm/lzw.h"
41 #include "dm/text.h"
42 
43 namespace DM {
44 
FieldAspect(uint16 native,uint16 base,uint16 transparent,byte mask,uint16 byteWidth,uint16 height,uint16 xPos,uint16 bitplane)45 FieldAspect::FieldAspect(uint16 native, uint16 base, uint16 transparent, byte mask, uint16 byteWidth, uint16 height, uint16 xPos, uint16 bitplane)
46 	: _nativeBitmapRelativeIndex(native), _baseStartUnitIndex(base), _transparentColor(transparent), _mask(mask),
47 	_byteWidth(byteWidth), _height(height), _xPos(xPos), _bitplaneWordCount(bitplane) {}
48 
FieldAspect()49 FieldAspect::FieldAspect() : _nativeBitmapRelativeIndex(0), _baseStartUnitIndex(0), _transparentColor(0),
50 	_mask(0), _byteWidth(0), _height(0), _xPos(0), _bitplaneWordCount(0) {}
51 
DoorFrames(Frame f1,Frame f2_1,Frame f2_2,Frame f2_3,Frame f3_1,Frame f3_2,Frame f3_3,Frame f4_1,Frame f4_2,Frame f4_3)52 DoorFrames::DoorFrames(Frame f1, Frame f2_1, Frame f2_2, Frame f2_3,
53 		Frame f3_1, Frame f3_2, Frame f3_3,
54 		Frame f4_1, Frame f4_2, Frame f4_3) {
55 	_closedOrDestroyed = f1;
56 	_vertical[0] = f2_1;
57 	_vertical[1] = f2_2;
58 	_vertical[2] = f2_3;
59 	_leftHorizontal[0] = f3_1;
60 	_leftHorizontal[1] = f3_2;
61 	_leftHorizontal[2] = f3_3;
62 	_rightHorizontal[0] = f4_1;
63 	_rightHorizontal[1] = f4_2;
64 	_rightHorizontal[2] = f4_3;
65 }
66 
DisplayMan(DMEngine * dmEngine)67 DisplayMan::DisplayMan(DMEngine *dmEngine) : _vm(dmEngine) {
68 	_bitmapScreen = nullptr;
69 	_bitmaps = nullptr;
70 	_grapItemCount = 0;
71 	_packedItemPos = nullptr;
72 	_bitmapCompressedByteCount = nullptr;
73 	_bitmapDecompressedByteCount = nullptr;
74 	_packedBitmaps = nullptr;
75 	_bitmaps = nullptr;
76 	_tmpBitmap = nullptr;
77 	_bitmapFloor = nullptr;
78 	_bitmapCeiling = nullptr;
79 	_currMapAllowedCreatureTypes = nullptr;
80 	_derivedBitmapByteCount = nullptr;
81 	_derivedBitmaps = nullptr;
82 
83 	_screenWidth = _screenHeight = 0;
84 	_championPortraitOrdinal = 0;
85 	_currMapViAltarIndex = 0;
86 	_drawFloorAndCeilingRequested = true;
87 
88 	for (int i = 0; i < 4; i++)
89 		_palChangesProjectile[i] = nullptr;
90 
91 	for (int i = 0; i < k3_AlcoveOrnCount; i++)
92 		_currMapAlcoveOrnIndices[i] = 0;
93 
94 	for (int i = 0; i < k1_FountainOrnCount; i++)
95 		_currMapFountainOrnIndices[i] = 0;
96 
97 	for (int i = 0; i < 2; i++) {
98 		for (int j = 0; j < 16; j++) {
99 			_currMapWallOrnInfo[j].nativeIndice = 0;
100 			_currMapWallOrnInfo[j].coordinateSet= 0;
101 			_currMapFloorOrnInfo[j].nativeIndice = 0;
102 			_currMapFloorOrnInfo[j].coordinateSet = 0;
103 		}
104 
105 		for (int j = 0; j < 17; j++) {
106 			_currMapDoorOrnInfo[j].nativeIndice = 0;
107 			_currMapDoorOrnInfo[j].coordinateSet = 0;
108 		}
109 	}
110 
111 	for (int i = 0; i < 16; i++) {
112 		_currMapWallOrnIndices[i] = 0;
113 		_currMapFloorOrnIndices[i] = 0;
114 	}
115 
116 	for (int i = 0; i < 18; i++)
117 		_currMapDoorOrnIndices[i] = 0;
118 
119 	_inscriptionThing = _vm->_thingNone;
120 	_useByteBoxCoordinates = false;
121 
122 	_bitmapCeiling = nullptr;
123 	_bitmapFloor = nullptr;
124 	_bitmapWallSetD3L2 = nullptr;
125 	_bitmapWallSetD3R2 = nullptr;
126 	_bitmapWallSetD3LCR = nullptr;
127 	_bitmapWallSetD2LCR = nullptr;
128 	_bitmapWallSetD1LCR = nullptr;
129 	_bitmapWallSetWallD0L = nullptr;
130 	_bitmapWallSetWallD0R = nullptr;
131 	_bitmapWallSetDoorFrameTopD2LCR = nullptr;
132 	_bitmapWallSetDoorFrameTopD1LCR = nullptr;
133 	_bitmapWallSetDoorFrameLeftD3L = nullptr;
134 	_bitmapWallSetDoorFrameLeftD3C = nullptr;
135 	_bitmapWallSetDoorFrameLeftD2C = nullptr;
136 	_bitmapWallSetDoorFrameLeftD1C = nullptr;
137 	_bitmapWallSetDoorFrameRightD1C = nullptr;
138 	_bitmapWallSetDoorFrameFront = nullptr;
139 	_bitmapViewport = nullptr;
140 
141 	_currentWallSet = -1;
142 	_currentFloorSet = -1;
143 
144 	_bitmapWallD3LCRFlipped = nullptr;
145 	_bitmapWallD2LCRFlipped = nullptr;
146 	_bitmapWallD1LCRFlipped = nullptr;
147 	_bitmapWallD0LFlipped = nullptr;
148 	_bitmapWallD0RFlipped = nullptr;
149 	_bitmapWallD3LCRNative = nullptr;
150 	_bitmapWallD2LCRNative = nullptr;
151 	_bitmapWallD1LCRNative = nullptr;
152 	_bitmapWallD0LNative = nullptr;
153 	_bitmapWallD0RNative = nullptr;
154 
155 	_paletteSwitchingEnabled = false;
156 	_dungeonViewPaletteIndex = 0;
157 
158 	for (uint16 i = 0; i < 16; ++i) {
159 		_paletteTopAndBottomScreen[i] = 0;
160 		_paletteMiddleScreen[i] = 0;
161 	}
162 
163 	for (uint16 i = 0; i < 32; i++)
164 		_blankBuffer[i] = 0;
165 
166 	_paletteFadeFrom = nullptr;
167 	for (uint16 i = 0; i < 16; ++i)
168 		_paletteFadeTemporary[i] = 0;
169 
170 	_refreshDungeonViewPaleteRequested = false;
171 
172 	initConstants();
173 }
174 
initConstants()175 void DisplayMan::initConstants() {
176 	const byte palChangesDoorButtonAndWallOrnD3[16] = {0, 0, 120, 30, 40, 30, 0, 60, 30, 90, 100, 110, 0, 10, 0, 20}; // @ G0198_auc_Graphic558_PaletteChanges_DoorButtonAndWallOrnament_D3
177 	const byte palChangesDoorButtonAndWallOrnD2[16] = {0, 120, 10, 30, 40, 30, 60, 70, 50, 90, 100, 110, 0, 20, 140, 130}; // @ G0199_auc_Graphic558_PaletteChanges_DoorButtonAndWallOrnament_D2
178 	const FieldAspect fieldAspects188[12] = { // @ G0188_as_Graphic558_FieldAspects
179 	/* { NativeBitmapRelativeIndex, BaseStartUnitIndex, Transparent color, Mask, ByteWidth, Height, X, BitPlaneWordCount } */
180 		FieldAspect(0, 63, 0x8A, 0xFF,  0,   0,  0, 64),  /* D3C */
181 		FieldAspect(0, 63, 0x0A, 0x80, 48,  51, 11, 64),  /* D3L */
182 		FieldAspect(0, 63, 0x0A, 0x00, 48,  51,  0, 64),  /* D3R */
183 		FieldAspect(0, 60, 0x8A, 0xFF,  0,   0,  0, 64),  /* D2C */
184 		FieldAspect(0, 63, 0x0A, 0x81, 40,  71,  5, 64),  /* D2L */
185 		FieldAspect(0, 63, 0x0A, 0x01, 40,  71,  0, 64),  /* D2R */
186 		FieldAspect(0, 61, 0x8A, 0xFF,  0,   0,  0, 64),  /* D1C */
187 		FieldAspect(0, 63, 0x0A, 0x82, 32, 111,  0, 64),  /* D1L */
188 		FieldAspect(0, 63, 0x0A, 0x02, 32, 111,  0, 64),  /* D1R */
189 		FieldAspect(0, 59, 0x8A, 0xFF,  0,   0,  0, 64),  /* D0C */
190 		FieldAspect(0, 63, 0x0A, 0x83, 16, 136,  0, 64),  /* D0L */
191 		FieldAspect(0, 63, 0x0A, 0x03, 16, 136,  0, 64)   /* D0R */
192 	};
193 
194 	const ExplosionAspect explosionAspects[k4_ExplosionAspectCount] = { // @ G0211_as_Graphic558_ExplosionAspects
195 		// ByteWidth, Height
196 		ExplosionAspect(80, 111),   // Fire
197 		ExplosionAspect(64,  97),   // Spell
198 		ExplosionAspect(80,  91),   // Poison
199 		ExplosionAspect(80,  91)    // Death
200 	};
201 
202 	const byte palChangeSmoke[16] = {0, 10, 20, 30, 40, 50, 120, 10, 80, 90, 100, 110, 120, 130, 140, 150}; // @ G0212_auc_Graphic558_PaletteChanges_Smoke
203 	const byte projectileScales[7] = {
204 		13,   /* D4 Back  */
205 		16,   /* D4 Front */
206 		19,   /* D3 Back  */
207 		22,   /* D3 Front */
208 		25,   /* D2 Back  */
209 		28,   /* D2 Front */
210 		32    /* D1 Back  */
211 	};
212 
213 	const Frame frameWalls163[12] = { // @ G0163_as_Graphic558_Frame_Walls
214 		/* { X1, X2, Y1, Y2, pixelWidth, Height, X, Y } */
215 		Frame(74, 149, 25,  75,  64,  51,  18, 0),  /* D3C */
216 		Frame(0,  83, 25,  75,  64,  51,  32, 0),   /* D3L */
217 		Frame(139, 223, 25,  75,  64,  51,   0, 0), /* D3R */
218 		Frame(60, 163, 20,  90,  72,  71,  16, 0),  /* D2C */
219 		Frame(0,  74, 20,  90,  72,  71,  61, 0),   /* D2L */
220 		Frame(149, 223, 20,  90,  72,  71,   0, 0), /* D2R */
221 		Frame(32, 191,  9, 119, 128, 111,  48, 0),  /* D1C */
222 		Frame(0,  63,  9, 119, 128, 111, 192, 0),   /* D1L */
223 		Frame(160, 223,  9, 119, 128, 111,   0, 0), /* D1R */
224 		Frame(0, 223,  0, 135,   0,   0,   0, 0),   /* D0C */
225 		Frame(0,  31,  0, 135,  16, 136,   0, 0),   /* D0L */
226 		Frame(192, 223,  0, 135,  16, 136,   0, 0)  /* D0R */
227 	};
228 
229 	const CreatureAspect creatureAspects219[k27_CreatureTypeCount] = { // @ G0219_as_Graphic558_CreatureAspects
230 	/* { FirstNativeBitmapRelativeIndex, FirstDerivedBitmapIndex, pixelWidthFront, HeightFront,
231 		 pixelWidthSide, HeightSide, pixelWidthAttack, HeightAttack, CoordinateSet / TransparentColor,
232 		 Replacement Color Set Index for color 10 / Replacement Color Set Index for color 9 } */
233 		CreatureAspect(0, 0, 56 ,  84, 56 ,  84, 56 ,  84, 0x1D, 0x01),    /* Creature #00 Giant Scorpion / Scorpion */
234 		CreatureAspect(4, 0, 32 ,  66,  0 ,   0, 32 ,  69, 0x0B, 0x20),    /* Creature #01 Swamp Slime / Slime Devil */
235 		CreatureAspect(6, 0, 24 ,  48, 24 ,  48,  0 ,   0, 0x0B, 0x00),    /* Creature #02 Giggler */
236 		CreatureAspect(10, 0, 32 ,  61,  0 ,   0, 32 ,  61, 0x24, 0x31),   /* Creature #03 Wizard Eye / Flying Eye */
237 		CreatureAspect(12, 0, 32 ,  64, 56 ,  64, 32 ,  64, 0x14, 0x34),   /* Creature #04 Pain Rat / Hellhound */
238 		CreatureAspect(16, 0, 24 ,  49, 40 ,  49,  0 ,   0, 0x18, 0x34),   /* Creature #05 Ruster */
239 		CreatureAspect(19, 0, 32 ,  60,  0 ,   0, 32 ,  60, 0x0D, 0x00),   /* Creature #06 Screamer */
240 		CreatureAspect(21, 0, 32 ,  43,  0 ,   0, 32 ,  64, 0x04, 0x00),   /* Creature #07 Rockpile / Rock pile */
241 		CreatureAspect(23, 0, 32 ,  83,  0 ,   0, 32 ,  93, 0x04, 0x00),   /* Creature #08 Ghost / Rive */
242 		CreatureAspect(25, 0, 32 , 101, 32 , 101, 32 , 101, 0x14, 0x00),   /* Creature #09 Stone Golem */
243 		CreatureAspect(29, 0, 32 ,  82, 32 ,  82, 32 ,  83, 0x04, 0x00),   /* Creature #10 Mummy */
244 		CreatureAspect(33, 0, 32 ,  80,  0 ,   0, 32 ,  99, 0x14, 0x00),   /* Creature #11 Black Flame */
245 		CreatureAspect(35, 0, 32 ,  80, 32 ,  80, 32 ,  76, 0x04, 0x00),   /* Creature #12 Skeleton */
246 		CreatureAspect(39, 0, 32 ,  96, 56 ,  93, 32 ,  90, 0x1D, 0x20),   /* Creature #13 Couatl */
247 		CreatureAspect(43, 0, 32 ,  49, 16 ,  49, 32 ,  56, 0x04, 0x30),   /* Creature #14 Vexirk */
248 		CreatureAspect(47, 0, 32 ,  59, 56 ,  43, 32 ,  67, 0x14, 0x78),   /* Creature #15 Magenta Worm / Worm */
249 		CreatureAspect(51, 0, 32 ,  83, 32 ,  74, 32 ,  74, 0x04, 0x65),   /* Creature #16 Trolin / Ant Man */
250 		CreatureAspect(55, 0, 24 ,  49, 24 ,  53, 24 ,  53, 0x24, 0x00),   /* Creature #17 Giant Wasp / Muncher */
251 		CreatureAspect(59, 0, 32 ,  89, 32 ,  89, 32 ,  89, 0x04, 0x00),   /* Creature #18 Animated Armour / Deth Knight */
252 		CreatureAspect(63, 0, 32 ,  84, 32 ,  84, 32 ,  84, 0x0D, 0xA9),   /* Creature #19 Materializer / Zytaz */
253 		CreatureAspect(67, 0, 56 ,  27,  0 ,   0, 56 ,  80, 0x04, 0x65),   /* Creature #20 Water Elemental */
254 		CreatureAspect(69, 0, 56 ,  77, 56 ,  81, 56 ,  77, 0x04, 0xA9),   /* Creature #21 Oitu */
255 		CreatureAspect(73, 0, 32 ,  87, 32 ,  89, 32 ,  89, 0x04, 0xCB),   /* Creature #22 Demon */
256 		CreatureAspect(77, 0, 32 ,  96, 32 ,  94, 32 ,  96, 0x04, 0x00),   /* Creature #23 Lord Chaos */
257 		CreatureAspect(81, 0, 64 ,  94, 72 ,  94, 64 ,  94, 0x04, 0xCB),   /* Creature #24 Red Dragon / Dragon */
258 		CreatureAspect(85, 0, 32 ,  93,  0 ,   0,  0 ,   0, 0x04, 0xCB),   /* Creature #25 Lord Order */
259 		CreatureAspect(86, 0, 32 ,  93,  0 ,   0,  0 ,   0, 0x04, 0xCB)    /* Creature #26 Grey Lord */
260 	};
261 	static ObjectAspect objectAspects209[k85_ObjAspectCount] = { // @ G0209_as_Graphic558_ObjectAspects
262 		/* FirstNativeBitmapRelativeIndex, FirstDerivedBitmapRelativeIndex, ByteWidth, Height, GraphicInfo, CoordinateSet */
263 		ObjectAspect(0,   0, 24, 27, 0x11, 0),
264 		ObjectAspect(2,   6, 24,  8, 0x00, 1),
265 		ObjectAspect(3,   8,  8, 18, 0x00, 1),
266 		ObjectAspect(4,  10,  8,  8, 0x00, 1),
267 		ObjectAspect(5,  12,  8,  4, 0x00, 1),
268 		ObjectAspect(6,  14, 16, 11, 0x00, 1),
269 		ObjectAspect(7,  16, 24, 13, 0x00, 0),
270 		ObjectAspect(8,  18, 32, 16, 0x00, 0),
271 		ObjectAspect(9,  20, 40, 24, 0x00, 0),
272 		ObjectAspect(10,  22, 16, 20, 0x00, 1),
273 		ObjectAspect(11,  24, 40, 20, 0x00, 0),
274 		ObjectAspect(12,  26, 32,  4, 0x00, 1),
275 		ObjectAspect(13,  28, 40,  8, 0x00, 1),
276 		ObjectAspect(14,  30, 32, 17, 0x00, 0),
277 		ObjectAspect(15,  32, 40, 17, 0x00, 2),
278 		ObjectAspect(16,  34, 16,  9, 0x00, 1),
279 		ObjectAspect(17,  36, 24,  5, 0x00, 1),
280 		ObjectAspect(18,  38, 16,  9, 0x00, 0),
281 		ObjectAspect(19,  40,  8,  4, 0x00, 1),
282 		ObjectAspect(20,  42, 32, 21, 0x00, 2),
283 		ObjectAspect(21,  44, 32, 25, 0x00, 2),
284 		ObjectAspect(22,  46, 32, 14, 0x00, 1),
285 		ObjectAspect(23,  48, 32, 26, 0x00, 2),
286 		ObjectAspect(24,  50, 32, 16, 0x00, 0),
287 		ObjectAspect(25,  52, 32, 16, 0x00, 0),
288 		ObjectAspect(26,  54, 16, 16, 0x00, 1),
289 		ObjectAspect(27,  56, 16, 15, 0x00, 1),
290 		ObjectAspect(28,  58, 16, 13, 0x00, 1),
291 		ObjectAspect(29,  60, 16, 10, 0x00, 1),
292 		ObjectAspect(30,  62, 40, 24, 0x00, 0),
293 		ObjectAspect(31,  64, 40,  9, 0x00, 1),
294 		ObjectAspect(32,  66, 16,  3, 0x00, 1),
295 		ObjectAspect(33,  68, 32,  5, 0x00, 1),
296 		ObjectAspect(34,  70, 40, 16, 0x00, 0),
297 		ObjectAspect(35,  72,  8,  7, 0x00, 1),
298 		ObjectAspect(36,  74, 32,  7, 0x00, 1),
299 		ObjectAspect(37,  76, 24, 14, 0x00, 0),
300 		ObjectAspect(38,  78, 16,  8, 0x00, 0),
301 		ObjectAspect(39,  80,  8,  3, 0x00, 1),
302 		ObjectAspect(40,  82, 40,  9, 0x00, 1),
303 		ObjectAspect(41,  84, 24, 14, 0x00, 0),
304 		ObjectAspect(42,  86, 40, 20, 0x00, 0),
305 		ObjectAspect(43,  88, 40, 15, 0x00, 1),
306 		ObjectAspect(44,  90, 32, 10, 0x00, 1),
307 		ObjectAspect(45,  92, 32, 19, 0x00, 0),
308 		ObjectAspect(46,  94, 40, 25, 0x00, 2),
309 		ObjectAspect(47,  96, 24,  7, 0x00, 1),
310 		ObjectAspect(48,  98,  8,  7, 0x00, 1),
311 		ObjectAspect(49, 100, 16,  5, 0x00, 1),
312 		ObjectAspect(50, 102,  8,  9, 0x00, 1),
313 		ObjectAspect(51, 104, 32, 11, 0x00, 1),
314 		ObjectAspect(52, 106, 32, 14, 0x00, 0),
315 		ObjectAspect(53, 108, 24, 20, 0x00, 0),
316 		ObjectAspect(54, 110, 16, 14, 0x00, 1),
317 		ObjectAspect(55, 112, 32, 23, 0x00, 0),
318 		ObjectAspect(56, 114, 24, 16, 0x00, 0),
319 		ObjectAspect(57, 116, 32, 25, 0x00, 0),
320 		ObjectAspect(58, 118, 24, 25, 0x00, 0),
321 		ObjectAspect(59, 120,  8,  8, 0x00, 1),
322 		ObjectAspect(60, 122,  8,  7, 0x00, 1),
323 		ObjectAspect(61, 124,  8,  8, 0x00, 1),
324 		ObjectAspect(62, 126,  8,  8, 0x00, 1),
325 		ObjectAspect(63, 128,  8,  5, 0x00, 1),
326 		ObjectAspect(64, 130,  8, 13, 0x01, 1),
327 		ObjectAspect(65, 134, 16, 13, 0x00, 1),
328 		ObjectAspect(66, 136, 16, 14, 0x00, 0),
329 		ObjectAspect(67, 138, 16, 10, 0x00, 1),
330 		ObjectAspect(68, 140,  8, 18, 0x00, 1),
331 		ObjectAspect(69, 142,  8, 17, 0x00, 1),
332 		ObjectAspect(70, 144, 32, 18, 0x00, 0),
333 		ObjectAspect(71, 146, 16, 23, 0x00, 0),
334 		ObjectAspect(72, 148, 16, 24, 0x00, 0),
335 		ObjectAspect(73, 150, 16, 15, 0x00, 0),
336 		ObjectAspect(74, 152,  8,  7, 0x00, 1),
337 		ObjectAspect(75, 154,  8, 15, 0x00, 1),
338 		ObjectAspect(76, 156,  8,  9, 0x00, 1),
339 		ObjectAspect(77, 158, 16, 14, 0x00, 0),
340 		ObjectAspect(78, 160,  8,  8, 0x00, 1),
341 		ObjectAspect(79, 162, 16,  9, 0x00, 1),
342 		ObjectAspect(80, 164,  8, 13, 0x01, 1),
343 		ObjectAspect(81, 168,  8, 18, 0x00, 1),
344 		ObjectAspect(82, 170, 24, 28, 0x00, 0),
345 		ObjectAspect(83, 172, 40, 13, 0x00, 1),
346 		ObjectAspect(84, 174,  8,  4, 0x00, 1),
347 		ObjectAspect(85, 176, 32, 17, 0x00, 0)
348 	};
349 
350 	static ProjectileAspect projectileAspect[k14_ProjectileAspectCount] = { // @ G0210_as_Graphic558_ProjectileAspects
351 		/* ProjectileAspect( FirstNativeBitmapRelativeIndex, FirstDerivedBitmapRelativeIndex, ByteWidth, Height, GraphicInfo ) */
352 		ProjectileAspect(0,   0, 32, 11, 0x0011),   /* Arrow */
353 		ProjectileAspect(3,  18, 16, 11, 0x0011),   /* Dagger */
354 		ProjectileAspect(6,  36, 24, 47, 0x0010),   /* Axe - Executioner */
355 		ProjectileAspect(9,  54, 32, 15, 0x0112),   /* Explosion Lightning Bolt */
356 		ProjectileAspect(11,  54, 32, 12, 0x0011),   /* Slayer */
357 		ProjectileAspect(14,  72, 24, 47, 0x0010),   /* Stone Club */
358 		ProjectileAspect(17,  90, 24, 47, 0x0010),   /* Club */
359 		ProjectileAspect(20, 108, 16, 11, 0x0011),   /* Poison Dart */
360 		ProjectileAspect(23, 126, 48, 18, 0x0011),   /* Storm - Side Splitter - Diamond Edge - Falchion - Ra Blade - Rapier - Biter - Samurai Sword - Sword - Dragon Fang */
361 		ProjectileAspect(26, 144,  8, 15, 0x0012),   /* Throwing Star */
362 		ProjectileAspect(28, 156, 16, 28, 0x0103),   /* Explosion Fireball */
363 		ProjectileAspect(29, 156, 16, 11, 0x0103),   /* Explosion Default */
364 		ProjectileAspect(30, 156, 16, 28, 0x0103),   /* Explosion Slime */
365 		ProjectileAspect(31, 156, 16, 24, 0x0103) /* Explosion Poison Bolt Poison Cloud */
366 	};
367 
368 	/* Atari ST: { 0x003, 0x055, 0x773, 0x420, 0x774, 0x000, 0x040, 0x500, 0x642, 0x775, 0x742, 0x760, 0x750, 0x000, 0x310, 0x776 }, RGB colors are different */
369 	static uint16 palCredits[16] = {0x006, 0x0AA, 0xFF6, 0x840, 0xFF8, 0x000, 0x080, 0xA00, 0xC84, 0xFFA, 0xF84, 0xFC0, 0xFA0, 0x000, 0x620, 0xFFC}; // @ G0019_aui_Graphic562_Palette_Credits
370 	static uint16 palDungeonView[6][16] = { // @ G0021_aaui_Graphic562_Palette_DungeonView
371 		/* Atari ST: { 0x000, 0x333, 0x444, 0x310, 0x066, 0x420, 0x040, 0x060, 0x700, 0x750, 0x643, 0x770, 0x222, 0x555, 0x007, 0x777 }, RGB colors are different */
372 		{ 0x000, 0x666, 0x888, 0x620, 0x0CC, 0x840, 0x080, 0x0C0, 0xF00, 0xFA0, 0xC86, 0xFF0, 0x444, 0xAAA, 0x00F, 0xFFF },
373 		/* Atari ST: { 0x000, 0x222, 0x333, 0x310, 0x066, 0x410, 0x030, 0x050, 0x600, 0x640, 0x532, 0x760, 0x111, 0x444, 0x006, 0x666 }, RGB colors are different */
374 		{ 0x000, 0x444, 0x666, 0x620, 0x0CC, 0x820, 0x060, 0x0A0, 0xC00, 0x000, 0x000, 0xFC0, 0x222, 0x888, 0x00C, 0xCCC },
375 		/* Atari ST: { 0x000, 0x111, 0x222, 0x210, 0x066, 0x310, 0x020, 0x040, 0x500, 0x530, 0x421, 0x750, 0x000, 0x333, 0x005, 0x555 }, RGB colors are different */
376 		{ 0x000, 0x222, 0x444, 0x420, 0x0CC, 0x620, 0x040, 0x080, 0xA00, 0x000, 0x000, 0xFA0, 0x000, 0x666, 0x00A, 0xAAA },
377 		/* Atari ST: { 0x000, 0x000, 0x111, 0x100, 0x066, 0x210, 0x010, 0x030, 0x400, 0x420, 0x310, 0x640, 0x000, 0x222, 0x004, 0x444 }, RGB colors are different */
378 		{ 0x000, 0x000, 0x222, 0x200, 0x0CC, 0x420, 0x020, 0x060, 0x800, 0x000, 0x000, 0xC80, 0x000, 0x444, 0x008, 0x888 },
379 		/* Atari ST: { 0x000, 0x000, 0x000, 0x000, 0x066, 0x100, 0x000, 0x020, 0x300, 0x310, 0x200, 0x530, 0x000, 0x111, 0x003, 0x333 }, RGB colors are different */
380 		{ 0x000, 0x000, 0x000, 0x000, 0x0CC, 0x200, 0x000, 0x040, 0x600, 0x000, 0x000, 0xA60, 0x000, 0x222, 0x006, 0x666 },
381 		/* Atari ST: { 0x000, 0x000, 0x000, 0x000, 0x066, 0x000, 0x000, 0x010, 0x200, 0x200, 0x100, 0x320, 0x000, 0x000, 0x002, 0x222 }, RGB colors are different */
382 		{ 0x000, 0x000, 0x000, 0x000, 0x0CC, 0x000, 0x000, 0x020, 0x400, 0x000, 0x000, 0x640, 0x000, 0x000, 0x004, 0x444 }
383 	};
384 
385 	static byte palChangesCreatureD3[16] = {0, 120, 10, 30, 40, 30, 0, 60, 30, 0, 0, 110, 0, 20, 0, 130}; // @ G0221_auc_Graphic558_PaletteChanges_Creature_D3
386 	static byte palChangesCreatureD2[16] = {0, 10, 20, 30, 40, 30, 60, 70, 50, 0, 0, 110, 120, 130, 140, 150}; // @ G0222_auc_Graphic558_PaletteChanges_Creature_D2
387 	static byte palChangesNoChanges[16] = {0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120, 130, 140, 150}; // @ G0017_auc_Graphic562_PaletteChanges_NoChanges
388 	static byte palChangesFloorOrnD3[16] = {0, 120, 10, 30, 40, 30, 0, 60, 30, 90, 100, 110, 0, 20, 140, 130}; // @ G0213_auc_Graphic558_PaletteChanges_FloorOrnament_D3
389 	static byte palChangesFloorOrnD2[16] = {0, 10, 20, 30, 40, 30, 60, 70, 50, 90, 100, 110, 120, 130, 140, 150}; // @ G0214_auc_Graphic558_PaletteChanges_FloorOrnament_D2
390 
391 	static byte const wallOrnamentCoordSets[8][13][6] = { // @ G0205_aaauc_Graphic558_WallOrnamentCoordinateSets
392 			/* { X1, X2, Y1, Y2, ByteWidth, Height } */
393 			{
394 					{80,  83, 41,  45,  8,   5},   /* D3L */
395 					{140, 143, 41,  45,  8,   5},  /* D3R */
396 					{16,  29, 39,  50,  8,  12},   /* D3L */
397 					{107, 120, 39,  50,  8,  12},  /* D3C */
398 					{187, 200, 39,  50,  8,  12},  /* D3R */
399 					{67,  77, 40,  49,  8,  10},   /* D2L */
400 					{146, 156, 40,  49,  8,  10},  /* D2R */
401 					{0,  17, 38,  55, 16,  18},    /* D2L */
402 					{102, 123, 38,  55, 16,  18},  /* D2C */
403 					{206, 223, 38,  55, 16,  18},  /* D2R */
404 					{48,  63, 38,  56,  8,  19},   /* D1L */
405 					{160, 175, 38,  56,  8,  19},  /* D1R */
406 					{96, 127, 36,  63, 16,  28}    /* D1C */
407 			},
408 			{
409 					{74,  82, 41,  60,  8,  20},   /* D3L */
410 					{141, 149, 41,  60,  8,  20},  /* D3R */
411 					{1,  47, 37,  63, 24,  27},    /* D3L */
412 					{88, 134, 37,  63, 24,  27},   /* D3C */
413 					{171, 217, 37,  63, 24,  27},  /* D3R */
414 					{61,  76, 38,  67,  8,  30},   /* D2L */
415 					{147, 162, 38,  67,  8,  30},  /* D2R */
416 					{0,  43, 37,  73, 32,  37},    /* D2L */
417 					{80, 143, 37,  73, 32,  37},   /* D2C */
418 					{180, 223, 37,  73, 32,  37},  /* D2R */
419 					{32,  63, 36,  83, 16,  48},   /* D1L */
420 					{160, 191, 36,  83, 16,  48},  /* D1R */
421 					{64, 159, 36,  91, 48,  56}    /* D1C */
422 			},
423 			{
424 					{80,  83, 66,  70,  8,   5},   /* D3L */
425 					{140, 143, 66,  70,  8,   5},  /* D3R */
426 					{16,  29, 64,  75,  8,  12},   /* D3L */
427 					{106, 119, 64,  75,  8,  12},  /* D3C */
428 					{187, 200, 64,  75,  8,  12},  /* D3R */
429 					{67,  77, 74,  83,  8,  10},   /* D2L */
430 					{146, 156, 74,  83,  8,  10},  /* D2R */
431 					{0,  17, 73,  90, 16,  18},    /* D2L */
432 					{100, 121, 73,  90, 16,  18},  /* D2C */
433 					{206, 223, 73,  90, 16,  18},  /* D2R */
434 					{48,  63, 84, 102,  8,  19},   /* D1L */
435 					{160, 175, 84, 102,  8,  19},  /* D1R */
436 					{96, 127, 92, 119, 16,  28}    /* D1C */
437 			},
438 			{
439 					{80,  83, 49,  53,  8,   5},   /* D3L */
440 					{140, 143, 49,  53,  8,   5},  /* D3R */
441 					{16,  29, 50,  61,  8,  12},   /* D3L */
442 					{106, 119, 50,  61,  8,  12},  /* D3C */
443 					{187, 200, 50,  61,  8,  12},  /* D3R */
444 					{67,  77, 53,  62,  8,  10},   /* D2L */
445 					{146, 156, 53,  62,  8,  10},  /* D2R */
446 					{0,  17, 55,  72, 16,  18},    /* D2L */
447 					{100, 121, 55,  72, 16,  18},  /* D2C */
448 					{206, 223, 55,  72, 16,  18},  /* D2R */
449 					{48,  63, 57,  75,  8,  19},   /* D1L */
450 					{160, 175, 57,  75,  8,  19},  /* D1R */
451 					{96, 127, 64,  91, 16,  28}    /* D1C */
452 			},
453 			{
454 					{75,  90, 40,  44,  8,   5},   /* D3L */
455 					{133, 148, 40,  44,  8,   5},  /* D3R */
456 					{1,  48, 44,  49, 24,   6},    /* D3L */
457 					{88, 135, 44,  49, 24,   6},   /* D3C */
458 					{171, 218, 44,  49, 24,   6},  /* D3R */
459 					{60,  77, 40,  46, 16,   7},   /* D2L */
460 					{146, 163, 40,  46, 16,   7},  /* D2R */
461 					{0,  35, 43,  50, 32,   8},    /* D2L */
462 					{80, 143, 43,  50, 32,   8},   /* D2C */
463 					{184, 223, 43,  50, 32,   8},  /* D2R */
464 					{32,  63, 41,  52, 16,  12},   /* D1L */
465 					{160, 191, 41,  52, 16,  12},  /* D1R */
466 					{64, 159, 41,  52, 48,  12}    /* D1C */
467 			},
468 			{
469 					{78,  85, 36,  51,  8,  16},   /* D3L */
470 					{138, 145, 36,  51,  8,  16},  /* D3R */
471 					{10,  41, 34,  53, 16,  20},   /* D3L */
472 					{98, 129, 34,  53, 16,  20},   /* D3C */
473 					{179, 210, 34,  53, 16,  20},  /* D3R */
474 					{66,  75, 34,  56,  8,  23},   /* D2L */
475 					{148, 157, 34,  56,  8,  23},  /* D2R */
476 					{0,  26, 33,  61, 24,  29},    /* D2L */
477 					{91, 133, 33,  61, 24,  29},   /* D2C */
478 					{194, 223, 33,  61, 24,  29},  /* D2R */
479 					{41,  56, 31,  65,  8,  35},   /* D1L */
480 					{167, 182, 31,  65,  8,  35},  /* D1R */
481 					{80, 143, 29,  71, 32,  43}    /* D1C */
482 			},
483 			{
484 					{75,  82, 25,  75,  8,  51},   /* D3L */
485 					{142, 149, 25,  75,  8,  51},  /* D3R */
486 					{12,  60, 25,  75, 32,  51},   /* D3L */
487 					{88, 136, 25,  75, 32,  51},   /* D3C */
488 					{163, 211, 25,  75, 32,  51},  /* D3R */
489 					{64,  73, 20,  90,  8,  71},   /* D2L */
490 					{150, 159, 20,  90,  8,  71},  /* D2R */
491 					{0,  38, 20,  90, 32,  71},    /* D2L */
492 					{82, 142, 20,  90, 32,  71},   /* D2C */
493 					{184, 223, 20,  90, 32,  71},  /* D2R */
494 					{41,  56,  9, 119,  8, 111},   /* D1L */
495 					{169, 184,  9, 119,  8, 111},  /* D1R */
496 					{64, 159,  9, 119, 48, 111}    /* D1C */
497 			},
498 			{
499 					{74,  85, 25,  75,  8,  51},   /* D3L */
500 					{137, 149, 25,  75,  8,  51},  /* D3R */
501 					{0,  75, 25,  75, 40,  51},    /* D3L Atari ST: {   0,  83, 25,  75, 48,  51 } */
502 					{74, 149, 25,  75, 40,  51},   /* D3C Atari ST: {  74, 149, 25,  75, 48,  51 } */
503 					{148, 223, 25,  75, 40,  51},  /* D3R Atari ST: { 139, 223, 25,  75, 48,  51 } */
504 					{60,  77, 20,  90, 16,  71},   /* D2L */
505 					{146, 163, 20,  90, 16,  71},  /* D2R */
506 					{0,  74, 20,  90, 56,  71},    /* D2L */
507 					{60, 163, 20,  90, 56,  71},   /* D2C */
508 					{149, 223, 20,  90, 56,  71},  /* D2R */
509 					{32,  63,  9, 119, 16, 111},   /* D1L */
510 					{160, 191,  9, 119, 16, 111},  /* D1R */
511 					{32, 191,  9, 119, 80, 111}    /* D1C */
512 			}
513 	};
514 
515 	static uint16 const doorOrnCoordSets[4][3][6] = { // @ G0207_aaauc_Graphic558_DoorOrnamentCoordinateSets
516 			/* { X1, X2, Y1, Y2, ByteWidth, Height } */
517 			{
518 					{17, 31,  8, 17,  8, 10},   /* D3LCR */
519 					{22, 42, 11, 23, 16, 13},   /* D2LCR */
520 					{32, 63, 13, 31, 16, 19}    /* D1LCR */
521 			},
522 			{
523 					{0, 47,  0, 40, 24, 41},    /* D3LCR */
524 					{0, 63,  0, 60, 32, 61},    /* D2LCR */
525 					{0, 95,  0, 87, 48, 88}     /* D1LCR */
526 			},
527 			{
528 					{17, 31, 15, 24,  8, 10},   /* D3LCR */
529 					{22, 42, 22, 34, 16, 13},   /* D2LCR */
530 					{32, 63, 31, 49, 16, 19}    /* D1LCR */
531 			},
532 			{
533 					{23, 35, 31, 39,  8,  9},   /* D3LCR */
534 					{30, 48, 41, 52, 16, 12},   /* D2LCR */
535 					{44, 75, 61, 79, 16, 19}    /* D1LCR */
536 			}
537 	};
538 
539 	static byte const doorButtonCoordSet[1] = {0}; // @ G0197_auc_Graphic558_DoorButtonCoordinateSet
540 	static uint16 const doorButtonCoordSets[1][4][6] = { // @ G0208_aaauc_Graphic558_DoorButtonCoordinateSets
541 			// X1, X2, Y1, Y2, ByteWidth, Height
542 			{ {199, 204, 41, 44, 8, 4},   /* D3R */
543 					{136, 141, 41, 44, 8, 4},   /* D3C */
544 					{144, 155, 42, 47, 8, 6},   /* D2C */
545 					{160, 175, 44, 52, 8, 9}    /* D1C */
546 			}
547 	};
548 
549 	_doorButtonCoordSet[0] = doorButtonCoordSet[0];
550 
551 	for(int a = 0; a < 1; ++a)
552 		for(int b = 0; b < 4; ++b)
553 			for(int c = 0; c < 6; ++c)
554 				_doorButtonCoordSets[a][b][c] = doorButtonCoordSets[a][b][c];
555 
556 	for(int a = 0; a < 8; ++a)
557 		for(int b = 0; b < 13; ++b)
558 			for(int c = 0; c < 6; ++c)
559 				_wallOrnamentCoordSets[a][b][c] = wallOrnamentCoordSets[a][b][c];
560 
561 	for(int a = 0; a < 4; ++a)
562 		for(int b = 0; b < 3; ++b)
563 			for(int c = 0; c < 6; ++c)
564 				_doorOrnCoordSets[a][b][c] = doorOrnCoordSets[a][b][c];
565 
566 	_frameWallD3R2 = Frame(208, 223, 25, 73, 8, 49, 0, 0); // @ G0712_s_Graphic558_Frame_Wall_D3R2
567 
568 	_doorFrameLeftD1C = Frame(43, 74, 14, 107, 16, 94, 0, 0); // @ G0170_s_Graphic558_Frame_DoorFrameLeft_D1C
569 	_doorFrameRightD1C = Frame(149, 180, 14, 107, 16, 94, 0, 0); // @ G0171_s_Graphic558_Frame_DoorFrameRight_D1C
570 
571 	for (int i = 0; i < 16; i++) {
572 		_palChangesDoorButtonAndWallOrnD3[i] = palChangesDoorButtonAndWallOrnD3[i];
573 		_palChangesDoorButtonAndWallOrnD2[i] = palChangesDoorButtonAndWallOrnD2[i];
574 		_palChangeSmoke[i] = palChangeSmoke[i];
575 		_palCredits[i] = palCredits[i];
576 		_palChangesCreatureD3[i] = palChangesCreatureD3[i];
577 		_palChangesCreatureD2[i] = palChangesCreatureD2[i];
578 		_palChangesNoChanges[i] = palChangesNoChanges[i];
579 		_palChangesFloorOrnD3[i] = palChangesFloorOrnD3[i];
580 		_palChangesFloorOrnD2[i] = palChangesFloorOrnD2[i];
581 		for (int j = 0; j < 6; j++)
582 			_palDungeonView[j][i] = palDungeonView[j][i];
583 	}
584 
585 	for (int i = 0; i < 12; i++) {
586 		_fieldAspects188[i] = fieldAspects188[i];
587 		_frameWalls163[i] = frameWalls163[i];
588 	}
589 
590 	for (int i = 0; i < 7; i++)
591 		_projectileScales[i] = projectileScales[i];
592 
593 	for (int i = 0; i < k4_ExplosionAspectCount; i++)
594 		_explosionAspects[i] = explosionAspects[i];
595 
596 	for (int i = 0; i < k27_CreatureTypeCount; i++)
597 		_creatureAspects219[i] = creatureAspects219[i];
598 
599 	for (int i = 0; i < k85_ObjAspectCount; i++)
600 		_objectAspects209[i] = objectAspects209[i];
601 
602 	for (int i = 0; i < k14_ProjectileAspectCount; i++)
603 		_projectileAspect[i] = projectileAspect[i];
604 
605 	_doorFrameD1C = new DoorFrames( // @ G0186_s_Graphic558_Frames_Door_D1C
606 	   Frame(64, 159, 17, 102, 48, 88, 0, 0),	 /* Closed Or Destroyed */
607 	   Frame(64, 159, 17, 38, 48, 88, 0, 66),	 /* Vertical Closed one fourth */
608 	   Frame(64, 159, 17, 60, 48, 88, 0, 44),	 /* Vertical Closed half */
609 	   Frame(64, 159, 17, 82, 48, 88, 0, 22),	 /* Vertical Closed three fourth */
610 	   Frame(64, 75, 17, 102, 48, 88, 36, 0),	 /* Left Horizontal Closed one fourth */
611 	   Frame(64, 87, 17, 102, 48, 88, 24, 0),	 /* Left Horizontal Closed half */
612 	   Frame(64, 99, 17, 102, 48, 88, 12, 0),	 /* Left Horizontal Closed three fourth */
613 	   Frame(148, 159, 17, 102, 48, 88, 48, 0), /* Right Horizontal Closed one fourth */
614 	   Frame(136, 159, 17, 102, 48, 88, 48, 0), /* Right Horizontal Closed half */
615 	   Frame(124, 159, 17, 102, 48, 88, 48, 0)	 /* Right Horizontal Closed three fourth */
616 	);
617 
618 	_boxThievesEyeViewPortVisibleArea = Box(64, 159, 19, 113); // @ G0106_s_Graphic558_Box_ThievesEye_ViewportVisibleArea
619 	_boxMovementArrows = Box(224, 319, 124, 168); // @ G0002_s_Graphic562_Box_MovementArrows
620 }
621 
~DisplayMan()622 DisplayMan::~DisplayMan() {
623 	delete[] _packedItemPos;
624 	delete[] _packedBitmaps;
625 	delete[] _bitmapScreen;
626 	delete[] _tmpBitmap;
627 	if (_bitmaps) {
628 		delete[] _bitmaps[0];
629 		delete[] _bitmaps;
630 	}
631 	delete[] _bitmapCompressedByteCount;
632 	delete[] _bitmapDecompressedByteCount;
633 
634 	delete[] _derivedBitmapByteCount;
635 	if (_derivedBitmaps) {
636 		for (uint16 i = 0; i < k730_DerivedBitmapMaximumCount; ++i)
637 			delete[] _derivedBitmaps[i];
638 		delete[] _derivedBitmaps;
639 	}
640 
641 	delete[] _bitmapCeiling;
642 	delete[] _bitmapFloor;
643 	delete[] _bitmapWallSetD3L2;
644 	delete[] _bitmapWallSetD3R2;
645 	delete[] _bitmapWallSetD3LCR;
646 	delete[] _bitmapWallSetD2LCR;
647 	delete[] _bitmapWallSetD1LCR;
648 	delete[] _bitmapWallSetWallD0L;
649 	delete[] _bitmapWallSetWallD0R;
650 	delete[] _bitmapWallSetDoorFrameTopD2LCR;
651 	delete[] _bitmapWallSetDoorFrameTopD1LCR;
652 	delete[] _bitmapWallSetDoorFrameLeftD3L;
653 	delete[] _bitmapWallSetDoorFrameLeftD3C;
654 	delete[] _bitmapWallSetDoorFrameLeftD2C;
655 	delete[] _bitmapWallSetDoorFrameLeftD1C;
656 	delete[] _bitmapWallSetDoorFrameRightD1C;
657 	delete[] _bitmapWallSetDoorFrameFront;
658 	delete[] _bitmapViewport;
659 
660 	delete[] _bitmapWallD3LCRFlipped;
661 	delete[] _bitmapWallD2LCRFlipped;
662 	delete[] _bitmapWallD1LCRFlipped;
663 	delete[] _bitmapWallD0LFlipped;
664 	delete[] _bitmapWallD0RFlipped;
665 
666 	delete _doorFrameD1C;
667 }
668 
getBitmapByteCount(uint16 pixelWidth,uint16 height)669 uint16 DisplayMan::getBitmapByteCount(uint16 pixelWidth, uint16 height) {
670 	return pixelWidth / 2 * height;
671 }
672 
setUpScreens(uint16 width,uint16 height)673 void DisplayMan::setUpScreens(uint16 width, uint16 height) {
674 	_screenWidth = width;
675 	_screenHeight = height;
676 	delete[] _tmpBitmap;
677 	delete[] _bitmapScreen;
678 	_bitmapScreen = new byte[_screenWidth * _screenHeight];
679 	fillScreen(kDMColorBlack);
680 
681 	_tmpBitmap = new byte[_screenWidth * _screenHeight];
682 }
683 
684 
initializeGraphicData()685 void DisplayMan::initializeGraphicData() {
686 	_bitmapCeiling = new byte[224 * 29];
687 	_bitmapFloor = new byte[224 * 70];
688 	_bitmapWallSetD3L2 = new byte[16 * 49];
689 	_bitmapWallSetD3R2 = new byte[16 * 49];
690 	_bitmapWallSetD3LCR = new byte[128 * 51];
691 	_bitmapWallSetD2LCR = new byte[144 * 71];
692 	_bitmapWallSetD1LCR = new byte[256 * 111];
693 	_bitmapWallSetWallD0L = new byte[32 * 136];
694 	_bitmapWallSetWallD0R = new byte[32 * 136];
695 	_bitmapWallSetDoorFrameTopD2LCR = new byte[96 * 3];
696 	_bitmapWallSetDoorFrameTopD1LCR = new byte[128 * 4];
697 	_bitmapWallSetDoorFrameLeftD3L = new byte[32 * 44];
698 	_bitmapWallSetDoorFrameLeftD3C = new byte[32 * 44];
699 	_bitmapWallSetDoorFrameLeftD2C = new byte[48 * 65];
700 	_bitmapWallSetDoorFrameLeftD1C = new byte[32 * 94];
701 	_bitmapWallSetDoorFrameRightD1C = new byte[32 * 94]();
702 	_bitmapWallSetDoorFrameFront = new byte[32 * 123];
703 	_bitmapViewport = new byte[224 * 136]();
704 
705 	if (!_derivedBitmapByteCount) {
706 		_derivedBitmapByteCount = new uint16[k730_DerivedBitmapMaximumCount];
707 	}
708 	if (!_derivedBitmaps) {
709 		_derivedBitmaps = new byte *[k730_DerivedBitmapMaximumCount];
710 		for (uint16 i = 0; i < k730_DerivedBitmapMaximumCount; ++i)
711 			_derivedBitmaps[i] = nullptr;
712 	}
713 
714 	_derivedBitmapByteCount[kDMDerivedBitmapViewport] = 112 * 136;
715 	_derivedBitmapByteCount[kDMDerivedBitmapThievesEyeVisibleArea] = 48 * 95;
716 	_derivedBitmapByteCount[kDMDerivedBitmapDamageToCreatureMedium] = 32 * 37;
717 	_derivedBitmapByteCount[kDMDerivedBitmapDamageToCreatureSmall] = 24 * 37;
718 
719 	for (int16 doorOrnamentIndex = k15_DoorOrnDestroyedMask; doorOrnamentIndex <= k16_DoorOrnThivesEyeMask; doorOrnamentIndex++) {
720 		_currMapDoorOrnInfo[doorOrnamentIndex].nativeIndice = doorOrnamentIndex + (kDMGraphicIdxDoorMaskDestroyed - k15_DoorOrnDestroyedMask);
721 		_currMapDoorOrnInfo[doorOrnamentIndex].coordinateSet = 1;
722 
723 		_derivedBitmapByteCount[doorOrnamentIndex * 2 + kDMDerivedBitmapFirstDoorOrnamentD3] = 24 * 41;
724 		_derivedBitmapByteCount[doorOrnamentIndex * 2 + kDMDerivedBitmapFirstDoorOrnamentD2] = 32 * 61;
725 	}
726 
727 	_currMapFloorOrnInfo[k15_FloorOrnFootprints].nativeIndice = kDMGraphicIdxFloorOrnD3LFootprints;
728 	_currMapFloorOrnInfo[k15_FloorOrnFootprints].coordinateSet = 1;
729 
730 	ObjectAspect *objectAspect = _objectAspects209;
731 	int16 derivedBitmapIndex;
732 	for (int16 objectAspectIndex = 0; objectAspectIndex < k85_ObjAspectCount; ++objectAspectIndex, ++objectAspect) {
733 		derivedBitmapIndex = kDMDerivedBitmapFirstObject + objectAspect->_firstDerivedBitmapRelativeIndex;
734 
735 		_derivedBitmapByteCount[derivedBitmapIndex++] = getScaledBitmapByteCount(objectAspect->_byteWidth, objectAspect->_height, k16_Scale_D3);
736 		_derivedBitmapByteCount[derivedBitmapIndex++] = getScaledBitmapByteCount(objectAspect->_byteWidth, objectAspect->_height, k20_Scale_D2);
737 
738 		if (getFlag(objectAspect->_graphicInfo, k0x0001_ObjectFlipOnRightMask)) {
739 			_derivedBitmapByteCount[derivedBitmapIndex] = _derivedBitmapByteCount[derivedBitmapIndex - 2];
740 			derivedBitmapIndex++;
741 			_derivedBitmapByteCount[derivedBitmapIndex] = _derivedBitmapByteCount[derivedBitmapIndex - 2];
742 			derivedBitmapIndex++;
743 		}
744 
745 		if (getFlag(objectAspect->_graphicInfo, k0x0010_ObjectAlcoveMask)) {
746 			_derivedBitmapByteCount[derivedBitmapIndex] = _derivedBitmapByteCount[derivedBitmapIndex - 2];
747 			derivedBitmapIndex++;
748 			_derivedBitmapByteCount[derivedBitmapIndex] = _derivedBitmapByteCount[derivedBitmapIndex - 2];
749 		}
750 	}
751 
752 	ProjectileAspect *projectileAspect = _projectileAspect;
753 	for (int16 projectileAspectIndex = 0; projectileAspectIndex < k14_ProjectileAspectCount; projectileAspectIndex++, projectileAspect++) {
754 		if (!getFlag(projectileAspect->_graphicInfo, k0x0100_ProjectileScaleWithKineticEnergyMask)) {
755 			derivedBitmapIndex = kDMDerivedBitmapFirstProjectile + projectileAspect->_firstDerivedBitmapRelativeIndex;
756 
757 			for (int16 projectileScaleIndex = 0; projectileScaleIndex < 6; projectileScaleIndex++) {
758 				int16 bitmapByteCount = getScaledBitmapByteCount(projectileAspect->_byteWidth, projectileAspect->_height, _projectileScales[projectileScaleIndex]);
759 				_derivedBitmapByteCount[derivedBitmapIndex] = bitmapByteCount;
760 
761 				if (getFlag(projectileAspect->_graphicInfo, k0x0003_ProjectileAspectTypeMask) != k3_ProjectileAspectHasNone) {
762 					_derivedBitmapByteCount[derivedBitmapIndex + 6] = bitmapByteCount;
763 
764 					if (getFlag(projectileAspect->_graphicInfo, k0x0003_ProjectileAspectTypeMask) != k2_ProjectileAspectHasRotation)
765 						_derivedBitmapByteCount[derivedBitmapIndex + 12] = bitmapByteCount;
766 				}
767 			}
768 		}
769 	}
770 
771 	_palChangesProjectile[0] = _palChangesFloorOrnD3;
772 	_palChangesProjectile[1] = _palChangesFloorOrnD2;
773 	_palChangesProjectile[2] = _palChangesProjectile[3] = _palChangesNoChanges;
774 
775 	derivedBitmapIndex = kDMDerivedBitmapFirstExplosion;
776 	ExplosionAspect *expAsp = _explosionAspects;
777 	for (uint16 expAspIndex = 0; expAspIndex < k4_ExplosionAspectCount; ++expAspIndex, expAsp++) {
778 		for (int16 scale = 4; scale < 32; scale += 2)
779 			_derivedBitmapByteCount[derivedBitmapIndex++] = getScaledBitmapByteCount(expAsp->_byteWidth, expAsp->_height, scale);
780 
781 		if (expAspIndex == kDMExplosionAspectSmoke)
782 			_derivedBitmapByteCount[derivedBitmapIndex++] = expAsp->_byteWidth * expAsp->_height;
783 	}
784 
785 	derivedBitmapIndex = kDMDerivedBitmapFirstCreature;
786 	CreatureAspect *creatureAsp;
787 	for (int16 creatureIndex = 0; creatureIndex < k27_CreatureTypeCount; creatureIndex++) {
788 		creatureAsp = &_creatureAspects219[creatureIndex];
789 
790 		int16 creatureGraphicInfo = _vm->_dungeonMan->_creatureInfos[creatureIndex]._graphicInfo;
791 		creatureAsp->_firstDerivedBitmapIndex = derivedBitmapIndex;
792 
793 		int16 creatureFrontBitmapD3PixelCount = getScaledBitmapByteCount(creatureAsp->_byteWidthFront, creatureAsp->_heightFront, k16_Scale_D3);
794 		_derivedBitmapByteCount[derivedBitmapIndex++] = creatureFrontBitmapD3PixelCount;
795 
796 		int16 creatureFrontBitmapD2PixelCount = getScaledBitmapByteCount(creatureAsp->_byteWidthFront, creatureAsp->_heightFront, k20_Scale_D2);
797 		_derivedBitmapByteCount[derivedBitmapIndex++] = creatureFrontBitmapD2PixelCount;
798 
799 		if (getFlag(creatureGraphicInfo, kDMCreatureMaskSide)) {
800 			_derivedBitmapByteCount[derivedBitmapIndex++] = getScaledBitmapByteCount(creatureAsp->_byteWidthSide, creatureAsp->_heightSide, k16_Scale_D3);
801 			_derivedBitmapByteCount[derivedBitmapIndex++] = getScaledBitmapByteCount(creatureAsp->_byteWidthSide, creatureAsp->_heightSide, k20_Scale_D2);
802 		}
803 
804 		if (getFlag(creatureGraphicInfo, kDMCreatureMaskBack)) {
805 			_derivedBitmapByteCount[derivedBitmapIndex++] = creatureFrontBitmapD3PixelCount;
806 			_derivedBitmapByteCount[derivedBitmapIndex++] = creatureFrontBitmapD2PixelCount;
807 		}
808 
809 		if (getFlag(creatureGraphicInfo, kDMCreatureMaskAttack)) {
810 			_derivedBitmapByteCount[derivedBitmapIndex++] = getScaledBitmapByteCount(creatureAsp->_byteWidthAttack, creatureAsp->_heightAttack, k16_Scale_D3);
811 			_derivedBitmapByteCount[derivedBitmapIndex++] = getScaledBitmapByteCount(creatureAsp->_byteWidthAttack, creatureAsp->_heightAttack, k20_Scale_D2);
812 		}
813 
814 		int16 additionalFronGraphicCount = getFlag(creatureGraphicInfo, kDMCreatureMaskAdditional);
815 		if (additionalFronGraphicCount) {
816 			do {
817 				_derivedBitmapByteCount[derivedBitmapIndex++] = creatureAsp->_byteWidthFront * creatureAsp->_heightFront;
818 				_derivedBitmapByteCount[derivedBitmapIndex++] = getScaledBitmapByteCount(creatureAsp->_byteWidthFront, creatureAsp->_heightFront, k16_Scale_D3);
819 				_derivedBitmapByteCount[derivedBitmapIndex++] = getScaledBitmapByteCount(creatureAsp->_byteWidthFront, creatureAsp->_heightFront, k20_Scale_D2);
820 			} while (--additionalFronGraphicCount);
821 		}
822 	}
823 }
824 
loadGraphics()825 void DisplayMan::loadGraphics() {
826 	Common::File f;
827 	f.open("graphics.dat");
828 	_grapItemCount = f.readUint16BE();
829 
830 	delete[] _bitmapCompressedByteCount;
831 	_bitmapCompressedByteCount = new uint32[_grapItemCount];
832 	for (uint16 i = 0; i < _grapItemCount; ++i)
833 		_bitmapCompressedByteCount[i] = f.readUint16BE();
834 
835 	delete[] _bitmapDecompressedByteCount;
836 	_bitmapDecompressedByteCount = new uint32[_grapItemCount];
837 	for (uint16 i = 0; i < _grapItemCount; ++i)
838 		_bitmapDecompressedByteCount[i] = f.readUint16BE();
839 
840 	delete[] _packedItemPos;
841 	_packedItemPos = new uint32[_grapItemCount + 1];
842 	_packedItemPos[0] = 0;
843 	for (uint16 i = 1; i < _grapItemCount + 1; ++i) {
844 		_packedItemPos[i] = _packedItemPos[i - 1] + _bitmapDecompressedByteCount[i - 1];
845 	}
846 
847 	delete[] _packedBitmaps;
848 	_packedBitmaps = new uint8[_packedItemPos[_grapItemCount]];
849 
850 	LZWdecompressor lzw;
851 	Common::Array<byte> tmpBuffer;
852 	f.seek(2 + _grapItemCount * 4);
853 	for (uint32 i = 0; i < _grapItemCount; ++i) {
854 		byte *bitmap = _packedBitmaps + _packedItemPos[i];
855 		f.read(bitmap, _bitmapCompressedByteCount[i]);
856 		if (_bitmapCompressedByteCount[i] != _bitmapDecompressedByteCount[i]) {
857 			tmpBuffer.reserve(_bitmapDecompressedByteCount[i]);
858 			Common::MemoryReadStream stream(bitmap, _bitmapCompressedByteCount[i]);
859 			lzw.decompress(stream, _bitmapCompressedByteCount[i], tmpBuffer.begin());
860 			memcpy(bitmap, tmpBuffer.begin(), _bitmapDecompressedByteCount[i]);
861 		}
862 	}
863 
864 	f.close();
865 	unpackGraphics();
866 }
867 
unpackGraphics()868 void DisplayMan::unpackGraphics() {
869 	uint32 unpackedBitmapsSize = 0;
870 	for (uint16 i = 0; i <= 20; ++i)
871 		unpackedBitmapsSize += getPixelWidth(i) * getPixelHeight(i);
872 	for (uint16 i = 22; i <= 532; ++i)
873 		unpackedBitmapsSize += getPixelWidth(i) * getPixelHeight(i);
874 	unpackedBitmapsSize += (5 + 1) * 6 * 128; // 5 x 6 characters, 128 of them, +1 for convenience padding
875 	// graphics items go from 0-20 and 22-532 inclusive, _unpackedItemPos 21 and 22 are there for indexing convenience
876 	if (_bitmaps) {
877 		delete[] _bitmaps[0];
878 		delete[] _bitmaps;
879 	}
880 	_bitmaps = new byte *[575]; // largest graphic indice (i think)
881 	_bitmaps[0] = new byte[unpackedBitmapsSize];
882 	loadIntoBitmap(0, _bitmaps[0]);
883 	for (uint16 i = 1; i <= 20; ++i) {
884 		_bitmaps[i] = _bitmaps[i - 1] + getPixelWidth(i - 1) * getPixelHeight(i - 1);
885 		loadIntoBitmap(i, _bitmaps[i]);
886 	}
887 	_bitmaps[22] = _bitmaps[20] + getPixelWidth(20) * getPixelHeight(20);
888 	for (uint16 i = 23; i <= 532; ++i) {
889 		_bitmaps[i] = _bitmaps[i - 1] + getPixelWidth(i - 1) * getPixelHeight(i - 1);
890 		loadIntoBitmap(i, _bitmaps[i]);
891 	}
892 	_bitmaps[kDMGraphicIdxFont] = _bitmaps[532] + getPixelWidth(532) * getPixelHeight(532);
893 	loadFNT1intoBitmap(kDMGraphicIdxFont, _bitmaps[kDMGraphicIdxFont]);
894 }
895 
loadFNT1intoBitmap(uint16 index,byte * destBitmap)896 void DisplayMan::loadFNT1intoBitmap(uint16 index, byte *destBitmap) {
897 	uint8 *data = _packedBitmaps + _packedItemPos[index];
898 
899 	for (uint16 i = 0; i < 6; i++) {
900 		for (uint16 w = 0; w < 128; ++w) {
901 			*destBitmap++ = kDMColorBlack;
902 
903 			uint16 nextByte = *data++;
904 			for (int16 pixel = 4; pixel >= 0; --pixel) {
905 				*destBitmap++ = (nextByte >> pixel) & 0x1;
906 			}
907 		}
908 	}
909 }
910 
allocateFlippedWallBitmaps()911 void DisplayMan::allocateFlippedWallBitmaps() {
912 	_bitmapWallD3LCRFlipped = new byte[128 * 51];
913 	_bitmapWallD2LCRFlipped = new byte[144 * 71];
914 	_bitmapWallD1LCRFlipped = new byte[256 * 111];
915 	_bitmapWallD0LFlipped = new byte[32 * 136];
916 	_bitmapWallD0RFlipped = new byte[32 * 136];
917 }
918 
drawDoorBitmap(Frame * frame)919 void DisplayMan::drawDoorBitmap(Frame *frame) {
920 	if (frame->_srcByteWidth) {
921 		blitToBitmap(_tmpBitmap, _bitmapViewport, frame->_box, frame->_srcX, frame->_srcY,
922 						  frame->_srcByteWidth, k112_byteWidthViewport, kDMColorFlesh, frame->_srcHeight, k136_heightViewport);
923 	}
924 }
925 
drawDoorFrameBitmapFlippedHorizontally(byte * bitmap,Frame * frame)926 void DisplayMan::drawDoorFrameBitmapFlippedHorizontally(byte *bitmap, Frame *frame) {
927 	if (frame->_srcByteWidth) {
928 		flipBitmapHorizontal(bitmap, frame->_srcByteWidth, frame->_srcHeight);
929 		blitToBitmap(bitmap, _bitmapViewport, frame->_box, frame->_srcX, frame->_srcY,
930 						  frame->_srcByteWidth, k112_byteWidthViewport, kDMColorFlesh, frame->_srcHeight, k136_heightViewport);
931 	}
932 }
933 
drawDoorButton(int16 doorButtonOrdinal,DoorButton doorButton)934 void DisplayMan::drawDoorButton(int16 doorButtonOrdinal, DoorButton doorButton) {
935 	DungeonMan &dungeon = *_vm->_dungeonMan;
936 
937 	if (doorButtonOrdinal) {
938 		doorButtonOrdinal--;
939 
940 		assert(doorButtonOrdinal == 0);
941 
942 		int16 nativeBitmapIndex = doorButtonOrdinal + kDMGraphicIdxFirstDoorButton;
943 		int coordSet = _doorButtonCoordSet[doorButtonOrdinal];
944 		uint16 *coordSetRedEagle = _doorButtonCoordSets[coordSet][doorButton];
945 
946 		byte *bitmap = nullptr;
947 		if (doorButton == kDMDoorButtonD1C) {
948 			bitmap = getNativeBitmapOrGraphic(nativeBitmapIndex);
949 
950 			dungeon._dungeonViewClickableBoxes[kDMViewCellDoorButtonOrWallOrn]._rect.left = coordSetRedEagle[0];
951 			dungeon._dungeonViewClickableBoxes[kDMViewCellDoorButtonOrWallOrn]._rect.right = coordSetRedEagle[1];
952 			dungeon._dungeonViewClickableBoxes[kDMViewCellDoorButtonOrWallOrn]._rect.top = coordSetRedEagle[2];
953 			dungeon._dungeonViewClickableBoxes[kDMViewCellDoorButtonOrWallOrn]._rect.bottom = coordSetRedEagle[3];
954 		} else {
955 			doorButtonOrdinal = kDMDerivedBitmapFirstDoorButton + (doorButtonOrdinal * 2) + ((doorButton != kDMDoorButtonD3R) ? 0 : (int16)doorButton - 1);
956 			if (!isDerivedBitmapInCache(doorButtonOrdinal)) {
957 				uint16 *coordSetBlueGoat = _doorButtonCoordSets[coordSet][kDMDoorButtonD1C];
958 				byte *bitmapNative = getNativeBitmapOrGraphic(nativeBitmapIndex);
959 				blitToBitmapShrinkWithPalChange(bitmapNative, getDerivedBitmap(doorButtonOrdinal),
960 													 coordSetBlueGoat[4] << 1, coordSetBlueGoat[5],
961 													 // modified code line
962 													 coordSetRedEagle[4] << 1,
963 													 coordSetRedEagle[5],
964 													 (doorButton == kDMDoorButtonD2C) ? _palChangesDoorButtonAndWallOrnD2 : _palChangesDoorButtonAndWallOrnD3);
965 
966 				addDerivedBitmap(doorButtonOrdinal);
967 			}
968 			bitmap = getDerivedBitmap(doorButtonOrdinal);
969 		}
970 		Box blitBox(coordSetRedEagle[0], coordSetRedEagle[1], coordSetRedEagle[2], coordSetRedEagle[3]);
971 		blitToBitmap(bitmap, _bitmapViewport, blitBox, 0, 0,
972 						  coordSetRedEagle[4], k112_byteWidthViewport, kDMColorFlesh, coordSetRedEagle[5], k136_heightViewport);
973 	}
974 }
975 
viewportSetPalette(uint16 * middleScreenPalette,uint16 * topAndBottomScreen)976 void DisplayMan::viewportSetPalette(uint16 *middleScreenPalette, uint16 *topAndBottomScreen) {
977 	if (middleScreenPalette && topAndBottomScreen)
978 		buildPaletteChangeCopperList(middleScreenPalette, topAndBottomScreen);
979 
980 	viewportBlitToScreen();
981 }
982 
viewportBlitToScreen()983 void DisplayMan::viewportBlitToScreen() {
984 	Box box(0, 223, 33, 168);
985 
986 	blitToBitmap(_bitmapViewport, _bitmapScreen, box, 0, 0, k112_byteWidthViewport, k160_byteWidthScreen, kDMColorNoTransparency,
987 					  k136_heightViewport, k200_heightScreen);
988 }
989 
loadIntoBitmap(uint16 index,byte * destBitmap)990 void DisplayMan::loadIntoBitmap(uint16 index, byte *destBitmap) {
991 	uint8 *data = _packedBitmaps + _packedItemPos[index];
992 
993 	uint16 width = READ_BE_UINT16(data);
994 	uint16 height = READ_BE_UINT16(data + 2);
995 	uint16 nextByteIndex = 4;
996 
997 	for (int32 k = 0; k < width * height;) {
998 		uint8 nextByte = data[nextByteIndex++];
999 		uint8 nibble1 = (nextByte & 0xF0) >> 4;
1000 		uint8 nibble2 = (nextByte & 0x0F);
1001 		if (nibble1 <= 7) {
1002 			for (int j = 0; j < nibble1 + 1; ++j)
1003 				destBitmap[k++] = nibble2;
1004 		} else if (nibble1 == 0x8) {
1005 			uint8 byte1 = data[nextByteIndex++];
1006 			for (int j = 0; j < byte1 + 1; ++j)
1007 				destBitmap[k++] = nibble2;
1008 		} else if (nibble1 == 0xC) {
1009 			uint16 word1 = READ_BE_UINT16(data + nextByteIndex);
1010 			nextByteIndex += 2;
1011 			for (int j = 0; j < word1 + 1; ++j)
1012 				destBitmap[k++] = nibble2;
1013 		} else if (nibble1 == 0xB) {
1014 			uint8 byte1 = data[nextByteIndex++];
1015 for (int j = 0; j < byte1 + 1; ++j, ++k)
1016 				destBitmap[k] = destBitmap[k - width];
1017 			destBitmap[k++] = nibble2;
1018 		} else if (nibble1 == 0xF) {
1019 			uint16 word1 = READ_BE_UINT16(data + nextByteIndex);
1020 			nextByteIndex += 2;
1021 			for (int j = 0; j < word1 + 1; ++j, ++k)
1022 				destBitmap[k] = destBitmap[k - width];
1023 			destBitmap[k++] = nibble2;
1024 		} else if (nibble1 == 9) {
1025 			uint8 byte1 = data[nextByteIndex++];
1026 			if (byte1 % 2)
1027 				byte1++;
1028 			else
1029 				destBitmap[k++] = nibble2;
1030 
1031 			for (int j = 0; j < byte1 / 2; ++j) {
1032 				uint8 byte2 = data[nextByteIndex++];
1033 				destBitmap[k++] = (byte2 & 0xF0) >> 4;
1034 				destBitmap[k++] = byte2 & 0x0F;
1035 			}
1036 		}
1037 	}
1038 }
1039 
blitToBitmap(byte * srcBitmap,byte * destBitmap,const Box & box,uint16 srcX,uint16 srcY,uint16 srcByteWidth,uint16 destByteWidth,Color transparent,int16 srcHeight,int16 destHight)1040 void DisplayMan::blitToBitmap(byte *srcBitmap, byte *destBitmap, const Box &box, uint16 srcX, uint16 srcY, uint16 srcByteWidth,
1041 								   uint16 destByteWidth, Color transparent, int16 srcHeight, int16 destHight) {
1042 	uint16 srcWidth = srcByteWidth * 2;
1043 	uint16 destWidth = destByteWidth * 2;
1044 	for (uint16 y = 0; y < box._rect.bottom + 1 - box._rect.top; ++y) { // + 1 for inclusive boundaries
1045 		for (uint16 x = 0; x < box._rect.right + 1 - box._rect.left; ++x) { // + 1 for inclusive boundaries
1046 			if (srcX + x < srcWidth && y + srcY < srcHeight
1047 				&& box._rect.left + x < destWidth && y + box._rect.top < destHight) {
1048 				byte srcPixel = srcBitmap[srcWidth * (y + srcY) + srcX + x];
1049 				if (srcPixel != transparent)
1050 					destBitmap[destWidth * (y + box._rect.top) + box._rect.left + x] = srcPixel;
1051 			}
1052 		}
1053 	}
1054 }
1055 
fillScreenBox(Box & box,Color color)1056 void DisplayMan::fillScreenBox(Box &box, Color color) {
1057 	uint16 width = box._rect.right + 1 - box._rect.left; // + 1 for inclusive boundaries
1058 	for (int16 y = box._rect.top; y < box._rect.bottom + 1; ++y) // + 1 for inclusive boundaries
1059 		memset(_bitmapScreen + y * _screenWidth + box._rect.left, color, sizeof(byte) * width);
1060 }
1061 
fillBoxBitmap(byte * destBitmap,Box & box,Color color,int16 byteWidth,int16 height)1062 void DisplayMan::fillBoxBitmap(byte *destBitmap, Box &box, Color color, int16 byteWidth, int16 height) {
1063 	for (int16 y = box._rect.top; y < box._rect.bottom + 1; ++y) // + 1 for inclusive boundaries
1064 		memset(destBitmap + y * byteWidth * 2 + box._rect.left, color, sizeof(byte) * (box._rect.right - box._rect.left + 1)); // + 1 for inclusive boundaries
1065 }
1066 
blitBoxFilledWithMaskedBitmap(byte * src,byte * dest,byte * mask,byte * tmp,Box & box,int16 lastUnitIndex,int16 firstUnitIndex,int16 destByteWidth,Color transparent,int16 xPos,int16 yPos,int16 destHeight,int16 height2)1067 void DisplayMan::blitBoxFilledWithMaskedBitmap(byte *src, byte *dest, byte *mask, byte *tmp, Box& box,
1068 											   int16 lastUnitIndex, int16 firstUnitIndex, int16 destByteWidth, Color transparent,
1069 											   int16 xPos, int16 yPos, int16 destHeight, int16 height2) {
1070 
1071 	// FIXME: does not produce the same effect as the original
1072 
1073 	byte nextUnitIndex = firstUnitIndex;
1074 	bool useMask = !(transparent & k0x0080_BlitDoNotUseMask);
1075 	transparent = (Color)(transparent & ~(k0x0080_BlitDoNotUseMask)); // clear flag 0x0080
1076 	for (byte next_y = box._rect.top; next_y <= box._rect.bottom; next_y++) { // '<=' for inclusive boundaries
1077 		for (byte next_x = box._rect.left; next_x <= box._rect.right; next_x++) { // '<=' for inclusive boundaries
1078 			byte *nextDestPixel = dest + next_y * destByteWidth * 2 + next_x;
1079 			byte nextSrcPixel = src[nextUnitIndex];
1080 
1081 			if (nextSrcPixel != transparent) {
1082 				if (useMask && mask && *mask++) {
1083 					*nextDestPixel = *mask & nextSrcPixel;
1084 				} else
1085 					*nextDestPixel = nextSrcPixel;
1086 			}
1087 
1088 			if (++nextUnitIndex >= lastUnitIndex)
1089 				nextUnitIndex = 0; // 0 is not an error
1090 		}
1091 	}
1092 }
1093 
flipBitmapHorizontal(byte * bitmap,uint16 byteWidth,uint16 height)1094 void DisplayMan::flipBitmapHorizontal(byte *bitmap, uint16 byteWidth, uint16 height) {
1095 	uint16 width = byteWidth * 2;
1096 	for (uint16 y = 0; y < height; ++y) {
1097 		for (uint16 x = 0; x < width / 2; ++x)
1098 			SWAP<byte>(bitmap[y * width + x], bitmap[y * width + width - 1 - x]);
1099 	}
1100 }
1101 
flipBitmapVertical(byte * bitmap,uint16 byteWidth,uint16 height)1102 void DisplayMan::flipBitmapVertical(byte *bitmap, uint16 byteWidth, uint16 height) {
1103 	uint16 width = byteWidth * 2;
1104 	byte *tmp = new byte[width];
1105 
1106 	for (uint16 y = 0; y < height / 2; ++y) {
1107 		memmove(tmp, bitmap + y * width, width);
1108 		memmove(bitmap + y * width, bitmap + (height - 1 - y) * width, width);
1109 		memmove(bitmap + (height - 1 - y) * width, tmp, width);
1110 	}
1111 
1112 	delete[] tmp;
1113 }
1114 
getExplosionBitmap(uint16 explosionAspIndex,uint16 scale,int16 & returnByteWidth,int16 & returnHeight)1115 byte *DisplayMan::getExplosionBitmap(uint16 explosionAspIndex, uint16 scale, int16& returnByteWidth, int16& returnHeight) {
1116 	ExplosionAspect *explAsp = &_explosionAspects[explosionAspIndex];
1117 	if (scale > 32)
1118 		scale = 32;
1119 	int16 pixelWidth = getScaledDimension(explAsp->_byteWidth, scale);
1120 	int16 height = getScaledDimension(explAsp->_height, scale);
1121 	byte *bitmap;
1122 	int16 derBitmapIndex = (explosionAspIndex * 14) + scale / 2 + kDMDerivedBitmapFirstExplosion - 2;
1123 	if ((scale == 32) && (explosionAspIndex != kDMExplosionAspectSmoke))
1124 		bitmap = getNativeBitmapOrGraphic(explosionAspIndex + kDMGraphicIdxFirstExplosion);
1125 	else if (isDerivedBitmapInCache(derBitmapIndex))
1126 		bitmap = getDerivedBitmap(derBitmapIndex);
1127 	else {
1128 		byte *nativeBitmap = getNativeBitmapOrGraphic(MIN(explosionAspIndex, (uint16)kDMExplosionAspectPoison) + kDMGraphicIdxFirstExplosion);
1129 		bitmap = getDerivedBitmap(derBitmapIndex);
1130 		blitToBitmapShrinkWithPalChange(nativeBitmap, bitmap, explAsp->_byteWidth, explAsp->_height, pixelWidth * 2, height,
1131 			(explosionAspIndex == kDMExplosionAspectSmoke) ? _palChangeSmoke : _palChangesNoChanges);
1132 		addDerivedBitmap(derBitmapIndex);
1133 	}
1134 
1135 	returnByteWidth = pixelWidth;
1136 	returnHeight = height;
1137 	return bitmap;
1138 }
1139 
updateScreen()1140 void DisplayMan::updateScreen() {
1141 	_vm->_textMan->updateMessageArea();
1142 	// apply copper
1143 	for (uint32 i = 320 * 30; i < 320 * 170; ++i)
1144 		_bitmapScreen[i] += 16;
1145 	g_system->copyRectToScreen(_bitmapScreen, _screenWidth, 0, 0, _screenWidth, _screenHeight);
1146 
1147 	g_system->updateScreen();
1148 	for (uint32 i = 320 * 30; i < 320 * 170; ++i)
1149 		_bitmapScreen[i] -= 16;
1150 }
1151 
drawViewport(int16 palSwitchingRequestedState)1152 void DisplayMan::drawViewport(int16 palSwitchingRequestedState) {
1153 	static uint16 *dungeonViewCurrentPalette; // @ K0010_pui_DungeonViewCurrentPalette
1154 
1155 	// ignored code F0510_AMIGA_WaitBottomOfViewPort
1156 	if (palSwitchingRequestedState == k2_viewportAsBeforeSleepOrFreezeGame)
1157 		palSwitchingRequestedState = _paletteSwitchingEnabled ? 1 : 0;
1158 
1159 	if (_refreshDungeonViewPaleteRequested) {
1160 		dungeonViewCurrentPalette = _palDungeonView[_dungeonViewPaletteIndex];
1161 		_refreshDungeonViewPaleteRequested = false;
1162 		if (palSwitchingRequestedState == k0_viewportNotDungeonView)
1163 			_paletteSwitchingEnabled = true;
1164 		else
1165 			_paletteSwitchingEnabled = false;
1166 	}
1167 
1168 	if (palSwitchingRequestedState != (_paletteSwitchingEnabled ? 1 : 0)) {
1169 		if (palSwitchingRequestedState) {
1170 			viewportSetPalette(dungeonViewCurrentPalette, _paletteTopAndBottomScreen);
1171 			_paletteSwitchingEnabled = true;
1172 		} else {
1173 			viewportSetPalette(_paletteTopAndBottomScreen, _paletteTopAndBottomScreen);
1174 			_paletteSwitchingEnabled = false;
1175 		}
1176 	} else
1177 		viewportSetPalette(nullptr, nullptr);
1178 
1179 	updateScreen();
1180 }
1181 
getCurrentVgaBuffer()1182 byte *DisplayMan::getCurrentVgaBuffer() {
1183 	return _bitmapScreen;
1184 }
1185 
getPixelWidth(uint16 index)1186 uint16 DisplayMan::getPixelWidth(uint16 index) {
1187 	byte *data = _packedBitmaps + _packedItemPos[index];
1188 	return READ_BE_UINT16(data);
1189 }
1190 
getPixelHeight(uint16 index)1191 uint16 DisplayMan::getPixelHeight(uint16 index) {
1192 	uint8 *data = _packedBitmaps + _packedItemPos[index];
1193 	return READ_BE_UINT16(data + 2);
1194 }
1195 
copyBitmapAndFlipHorizontal(byte * srcBitmap,byte * destBitmap,uint16 byteWidth,uint16 height)1196 void DisplayMan::copyBitmapAndFlipHorizontal(byte *srcBitmap, byte *destBitmap, uint16 byteWidth, uint16 height) {
1197 	memmove(destBitmap, srcBitmap, byteWidth * 2 * height * sizeof(byte));
1198 	flipBitmapHorizontal(destBitmap, byteWidth, height);
1199 }
1200 
drawFloorOrnament(uint16 floorOrnOrdinal,ViewFloor viewFloorIndex)1201 void DisplayMan::drawFloorOrnament(uint16 floorOrnOrdinal, ViewFloor viewFloorIndex) {
1202 	static byte g191_floorOrnNativeBitmapndexInc[9] = { // @ G0191_auc_Graphic558_FloorOrnamentNativeBitmapIndexIncrements
1203 		0,   /* D3L */
1204 		1,   /* D3C */
1205 		0,   /* D3R */
1206 		2,   /* D2L */
1207 		3,   /* D2C */
1208 		2,   /* D2R */
1209 		4,   /* D1L */
1210 		5,   /* D1C */
1211 		4};  /* D1R */
1212 
1213 	static uint16 g206_floorOrnCoordSets[3][9][6] = { // @ G0206_aaauc_Graphic558_FloorOrnamentCoordinateSets
1214 		/* { X1, X2, Y1, Y2, ByteWidth, Height } */
1215 		{
1216 			{32,  79, 66,  71, 24,  6},   /* D3L */
1217 			{96, 127, 66,  71, 16,  6},   /* D3C */
1218 			{144, 191, 66,  71, 24,  6},  /* D3R */
1219 			{0,  63, 77,  87, 32, 11},    /* D2L */
1220 			{80, 143, 77,  87, 32, 11},   /* D2C */
1221 			{160, 223, 77,  87, 32, 11},  /* D2R */
1222 			{0,  31, 92, 116, 16, 25},    /* D1L */
1223 			{80, 143, 92, 116, 32, 25},   /* D1C */
1224 			{192, 223, 92, 116, 16, 25}   /* D1R */
1225 		},
1226 		{
1227 			{0,  95, 66,  74, 48,  9},    /* D3L */
1228 			{64, 159, 66,  74, 48,  9},   /* D3C */
1229 			{128, 223, 66,  74, 48,  9},  /* D3R */
1230 			{0,  79, 75,  89, 40, 15},    /* D2L */
1231 			{56, 167, 75,  89, 56, 15},   /* D2C */
1232 			{144, 223, 75,  89, 40, 15},  /* D2R */
1233 			{0,  63, 90, 118, 32, 29},    /* D1L */
1234 			{32, 191, 90, 118, 80, 29},   /* D1C */
1235 			{160, 223, 90, 118, 32, 29}   /* D1R */
1236 		},
1237 		{
1238 			{42,  57, 68,  72,  8,  5},   /* D3L */
1239 			{104, 119, 68,  72,  8,  5},  /* D3C */
1240 			{166, 181, 68,  72,  8,  5},  /* D3R */
1241 			{9,  40, 80,  85, 16,  6},    /* D2L */
1242 			{96, 127, 80,  85, 16,  6},   /* D2C */
1243 			{183, 214, 80,  85, 16,  6},  /* D2R */
1244 			{0,  15, 97, 108,  8, 12},    /* D1L */
1245 			{96, 127, 97, 108, 16, 12},   /* D1C */
1246 			{208, 223, 97, 108,  8, 12}   /* D1R */
1247 		}
1248 	};
1249 
1250 	if (!floorOrnOrdinal)
1251 		return;
1252 
1253 	bool drawFootprints = (getFlag(floorOrnOrdinal, kDMMaskFootprints) ? true : false);
1254 	if (!drawFootprints || clearFlag(floorOrnOrdinal, kDMMaskFootprints)) {
1255 		floorOrnOrdinal--;
1256 		uint16 floorOrnIndex = floorOrnOrdinal;
1257 		int16 nativeBitmapIndex = _currMapFloorOrnInfo[floorOrnIndex].nativeIndice
1258 			+ g191_floorOrnNativeBitmapndexInc[viewFloorIndex];
1259 		uint16 *coordSets = g206_floorOrnCoordSets[_currMapFloorOrnInfo[floorOrnIndex].coordinateSet][viewFloorIndex];
1260 		byte *bitmap;
1261 		if ((viewFloorIndex == kDMViewFloorD1R) || (viewFloorIndex == kDMViewFloorD2R)
1262 			|| (viewFloorIndex == kDMViewFloorD3R)
1263 			|| ((floorOrnIndex == k15_FloorOrnFootprints) && _useFlippedWallAndFootprintsBitmap &&
1264 			((viewFloorIndex == kDMViewFloorD1C) || (viewFloorIndex == kDMViewFloorD2C) || (viewFloorIndex == kDMViewFloorD3C)))) {
1265 			bitmap = _tmpBitmap;
1266 			copyBitmapAndFlipHorizontal(getNativeBitmapOrGraphic(nativeBitmapIndex), bitmap, coordSets[4], coordSets[5]);
1267 		} else
1268 			bitmap = getNativeBitmapOrGraphic(nativeBitmapIndex);
1269 
1270 		Box blitBox(coordSets[0], coordSets[1], coordSets[2], coordSets[3]);
1271 		blitToBitmap(bitmap, _bitmapViewport, blitBox, 0, 0, coordSets[4], k112_byteWidthViewport, kDMColorFlesh, coordSets[5], k136_heightViewport);
1272 	}
1273 
1274 	if (drawFootprints)
1275 		drawFloorOrnament(_vm->indexToOrdinal(k15_FloorOrnFootprints), viewFloorIndex);
1276 }
1277 
drawDoor(uint16 doorThingIndex,DoorState doorState,int16 * doorNativeBitmapIndices,int16 byteCount,DoorOrnament doorOrnament,DoorFrames * doorFrames)1278 void DisplayMan::drawDoor(uint16 doorThingIndex, DoorState doorState, int16 *doorNativeBitmapIndices, int16 byteCount, DoorOrnament doorOrnament, DoorFrames *doorFrames) {
1279 	if (doorState == kDMDoorStateOpen)
1280 		return;
1281 
1282 	ChampionMan &championMan = *_vm->_championMan;
1283 	DungeonMan &dungeon = *_vm->_dungeonMan;
1284 
1285 	DoorFrames *doorFramesTemp = doorFrames;
1286 	Door *door = (Door *)(dungeon._thingData[kDMThingTypeDoor]) + doorThingIndex;
1287 	uint16 doorType = door->getType();
1288 	memmove(_tmpBitmap, getNativeBitmapOrGraphic(doorNativeBitmapIndices[doorType]), byteCount * 2);
1289 	drawDoorOrnament(door->getOrnOrdinal(), doorOrnament);
1290 	if (getFlag(dungeon._currMapDoorInfo[doorType]._attributes, kDMMaskDoorInfoAnimated)) {
1291 		if (_vm->getRandomNumber(2))
1292 			flipBitmapHorizontal(_tmpBitmap, doorFramesTemp->_closedOrDestroyed._srcByteWidth, doorFramesTemp->_closedOrDestroyed._srcHeight);
1293 
1294 		if (_vm->getRandomNumber(2))
1295 			flipBitmapVertical(_tmpBitmap, doorFramesTemp->_closedOrDestroyed._srcByteWidth, doorFramesTemp->_closedOrDestroyed._srcHeight);
1296 	}
1297 
1298 	if ((doorFramesTemp == _doorFrameD1C) && championMan._party._event73Count_ThievesEye)
1299 		drawDoorOrnament(_vm->indexToOrdinal(k16_DoorOrnThivesEyeMask), kDMDoorOrnamentD1LCR);
1300 
1301 	if (doorState == kDMDoorStateClosed)
1302 		drawDoorBitmap(&doorFramesTemp->_closedOrDestroyed);
1303 	else if (doorState == kDMDoorStateDestroyed) {
1304 		drawDoorOrnament(_vm->indexToOrdinal(k15_DoorOrnDestroyedMask), doorOrnament);
1305 		drawDoorBitmap(&doorFramesTemp->_closedOrDestroyed);
1306 	} else {
1307 		int16 idx = doorState - 1;
1308 		if (door->opensVertically())
1309 			drawDoorBitmap(&doorFramesTemp->_vertical[idx]);
1310 		else {
1311 			drawDoorBitmap(&doorFramesTemp->_leftHorizontal[idx]);
1312 			drawDoorBitmap(&doorFramesTemp->_rightHorizontal[idx]);
1313 		}
1314 	}
1315 }
1316 
drawDoorOrnament(int16 doorOrnOrdinal,DoorOrnament doorOrnament)1317 void DisplayMan::drawDoorOrnament(int16 doorOrnOrdinal, DoorOrnament doorOrnament) {
1318 	static byte palChangesDoorOrnD3[16] = {0, 120, 10, 30, 40, 30, 0, 60, 30, 90, 100, 110, 0, 20, 0, 130}; // @ G0200_auc_Graphic558_PaletteChanges_DoorOrnament_D3
1319 	static byte palChangesDoorOrnd2[16] = {0, 10, 20, 30, 40, 30, 60, 70, 50, 90, 100, 110, 120, 130, 140, 150}; // @ G0201_auc_Graphic558_PaletteChanges_DoorOrnament_D2
1320 
1321 
1322 	int16 height = doorOrnOrdinal;
1323 
1324 	if (!height)
1325 		return;
1326 
1327 	int16 byteWidth;
1328 	height--;
1329 
1330 	int16 nativeBitmapIndex = _currMapDoorOrnInfo[height].nativeIndice;
1331 	int16 coordSetGreenToad = _currMapDoorOrnInfo[height].coordinateSet;
1332 	uint16 *coordSetOrangeElk = &_doorOrnCoordSets[coordSetGreenToad][doorOrnament][0];
1333 	byte *blitBitmap;
1334 	if (doorOrnament == kDMDoorOrnamentD1LCR) {
1335 		blitBitmap = getNativeBitmapOrGraphic(nativeBitmapIndex);
1336 		byteWidth = k48_byteWidth;
1337 		height = 88;
1338 	} else {
1339 		height = kDMDerivedBitmapFirstDoorOrnamentD3 + (height * 2) + doorOrnament;
1340 		if (!isDerivedBitmapInCache(height)) {
1341 			uint16 *coordSetRedEagle = &_doorOrnCoordSets[coordSetGreenToad][kDMDoorOrnamentD1LCR][0];
1342 			byte *nativeBitmap = getNativeBitmapOrGraphic(nativeBitmapIndex);
1343 			blitToBitmapShrinkWithPalChange(nativeBitmap, getDerivedBitmap(height), coordSetRedEagle[4] << 1, coordSetRedEagle[5], coordSetOrangeElk[1] - coordSetOrangeElk[0] + 1, coordSetOrangeElk[5], (doorOrnament == kDMDoorOrnamentD3LCR) ? palChangesDoorOrnD3 : palChangesDoorOrnd2);
1344 			addDerivedBitmap(height);
1345 		}
1346 		blitBitmap = getDerivedBitmap(height);
1347 		if (doorOrnament == kDMDoorOrnamentD3LCR) {
1348 			byteWidth = k24_byteWidth;
1349 			height = 41;
1350 		} else {
1351 			byteWidth = k32_byteWidth;
1352 			height = 61;
1353 		}
1354 	}
1355 
1356 	Box box(coordSetOrangeElk[0], coordSetOrangeElk[1], coordSetOrangeElk[2], coordSetOrangeElk[3]);
1357 	blitToBitmap(blitBitmap, _tmpBitmap, box, 0, 0, coordSetOrangeElk[4], byteWidth, kDMColorGold, coordSetOrangeElk[5], height);
1358 }
1359 
drawCeilingPit(int16 nativeBitmapIndex,Frame * frame,int16 mapX,int16 mapY,bool flipHorizontal)1360 void DisplayMan::drawCeilingPit(int16 nativeBitmapIndex, Frame *frame, int16 mapX, int16 mapY, bool flipHorizontal) {
1361 	DungeonMan &dungeon = *_vm->_dungeonMan;
1362 
1363 	int16 mapIndex = dungeon.getLocationAfterLevelChange(dungeon._currMapIndex, -1, &mapX, &mapY);
1364 
1365 	if (mapIndex < 0)
1366 		return;
1367 
1368 	int16 mapSquare = dungeon._dungeonMapData[mapIndex][mapX][mapY];
1369 	if ((Square(mapSquare).getType() == kDMElementTypePit) && getFlag(mapSquare, kDMSquareMaskPitOpen)) {
1370 		if (flipHorizontal)
1371 			drawFloorPitOrStairsBitmapFlippedHorizontally(nativeBitmapIndex, *frame);
1372 		else
1373 			drawFloorPitOrStairsBitmap(nativeBitmapIndex, *frame);
1374 	}
1375 }
1376 
blitToViewport(byte * bitmap,Box & box,int16 byteWidth,Color transparent,int16 height)1377 void DisplayMan::blitToViewport(byte *bitmap, Box& box, int16 byteWidth, Color transparent, int16 height) {
1378 	blitToBitmap(bitmap, _bitmapViewport, box, 0, 0, byteWidth, k112_byteWidthViewport, transparent, height, k136_heightViewport);
1379 }
1380 
blitToViewport(byte * bitmap,int16 * box,int16 byteWidth,Color transparent,int16 height)1381 void DisplayMan::blitToViewport(byte *bitmap, int16 *box, int16 byteWidth, Color transparent, int16 height) {
1382 	Box actualBox(box[0], box[1], box[2], box[3]);
1383 	blitToViewport(bitmap, actualBox, byteWidth, transparent, height);
1384 }
1385 
blitToScreen(byte * bitmap,const Box * box,int16 byteWidth,Color transparent,int16 height)1386 void DisplayMan::blitToScreen(byte *bitmap, const Box *box, int16 byteWidth, Color transparent, int16 height) {
1387 	_useByteBoxCoordinates = false;
1388 	blitToBitmap(bitmap, _bitmapScreen, *box, 0, 0, byteWidth, k160_byteWidthScreen, transparent, height, k200_heightScreen);
1389 }
1390 
drawWallSetBitmapWithoutTransparency(byte * bitmap,Frame & f)1391 void DisplayMan::drawWallSetBitmapWithoutTransparency(byte *bitmap, Frame &f) {
1392 	if (!f._srcByteWidth)
1393 		return;
1394 
1395 	blitToBitmap(bitmap, _bitmapViewport, f._box, f._srcX, f._srcY, f._srcByteWidth, k112_byteWidthViewport, kDMColorNoTransparency, f._srcHeight, k136_heightViewport);
1396 }
1397 
drawWallSetBitmap(byte * bitmap,Frame & f)1398 void DisplayMan::drawWallSetBitmap(byte *bitmap, Frame &f) {
1399 	if (!f._srcByteWidth)
1400 		return;
1401 
1402 	blitToBitmap(bitmap, _bitmapViewport, f._box, f._srcX, f._srcY, f._srcByteWidth, k112_byteWidthViewport, kDMColorFlesh, f._srcHeight, k136_heightViewport);
1403 }
1404 
1405 
drawSquareD3L(Direction dir,int16 posX,int16 posY)1406 void DisplayMan::drawSquareD3L(Direction dir, int16 posX, int16 posY) {
1407 	static Frame doorFrameLeftD3L = Frame(0, 31, 28, 70, 16, 43, 0, 0); // @ G0164_s_Graphic558_Frame_DoorFrameLeft_D3L
1408 	static Frame frameStairsUpFrontD3L = Frame(0, 79, 25, 70, 40, 46, 0, 0); // @ G0110_s_Graphic558_Frame_StairsUpFront_D3L
1409 	static Frame frameStairsDownFrontD3L = Frame(0, 79, 28, 68, 40, 41, 0, 0); // @ G0121_s_Graphic558_Frame_StairsDownFront_D3L
1410 	static Frame frameFloorPitD3L = Frame(0, 79, 66, 73, 40, 8, 0, 0); // @ G0140_s_Graphic558_Frame_FloorPit_D3L
1411 	static DoorFrames doorFrameD3L = DoorFrames( // @ G0179_s_Graphic558_Frames_Door_D3L
1412 	/* { X1, X2, Y1, Y2, ByteWidth, Height, X, Y } */
1413 		Frame(24, 71, 28, 67, 24, 41, 0, 0),   /* Closed Or Destroyed */
1414 		Frame(24, 71, 28, 38, 24, 41, 0, 30),  /* Vertical Closed one fourth */
1415 		Frame(24, 71, 28, 48, 24, 41, 0, 20),  /* Vertical Closed half */
1416 		Frame(24, 71, 28, 58, 24, 41, 0, 10),  /* Vertical Closed three fourth */
1417 		Frame(24, 29, 28, 67, 24, 41, 18, 0),  /* Left Horizontal Closed one fourth */
1418 		Frame(24, 35, 28, 67, 24, 41, 12, 0),  /* Left Horizontal Closed half */
1419 		Frame(24, 41, 28, 67, 24, 41, 6, 0),   /* Left Horizontal Closed three fourth */
1420 		Frame(66, 71, 28, 67, 24, 41, 24, 0),  /* Right Horizontal Closed one fourth */
1421 		Frame(60, 71, 28, 67, 24, 41, 24, 0),  /* Right Horizontal Closed half */
1422 		Frame(54, 71, 28, 67, 24, 41, 24, 0)   /* Right Horizontal Closed three fourth */
1423 	);
1424 
1425 	uint16 squareAspect[5];
1426 	CellOrder order = kDMCellOrderNone;
1427 	bool skip = false;
1428 	DungeonMan &dungeon = *_vm->_dungeonMan;
1429 
1430 	dungeon.setSquareAspect(squareAspect, dir, posX, posY);
1431 	switch (squareAspect[kDMSquareAspectElement]) {
1432 	case kDMElementTypeStairsFront:
1433 		if (squareAspect[kDMSquareAspectStairsUp])
1434 			drawFloorPitOrStairsBitmap(_stairsNativeBitmapIndexUpFrontD3L, frameStairsUpFrontD3L);
1435 		else
1436 			drawFloorPitOrStairsBitmap(_stairsNativeBitmapIndexDownFrontD3L, frameStairsDownFrontD3L);
1437 		order = kDMCellOrderBackLeftBackRightFrontLeftFrontRight;
1438 		/* BUG0_64 Floor ornaments are drawn over open pits. There is no check to prevent drawing floor ornaments over open pits */
1439 		drawFloorOrnament(squareAspect[kDMSquareAspectFloorOrn], kDMViewFloorD3L);
1440 		break;
1441 	case kDMElementTypeWall:
1442 		drawWallSetBitmap(_bitmapWallSetD3LCR, _frameWalls163[kDMViewSquareD3L]);
1443 		isDrawnWallOrnAnAlcove(squareAspect[kDMSquareAspectRightWallOrnOrd], kDMViewWallD3LRight);
1444 		if (isDrawnWallOrnAnAlcove(squareAspect[kDMSquareFrontWallOrnOrd], kDMViewWallD3LFront))
1445 			order = kDMCellOrderAlcove;
1446 		else
1447 			return;
1448 		break;
1449 	case kDMElementTypeDoorSide:
1450 	case kDMElementTypeStairsSide:
1451 		order = kDMCellOrderBackLeftBackRightFrontRight;
1452 		/* BUG0_64 Floor ornaments are drawn over open pits. There is no check to prevent drawing floor ornaments over open pits */
1453 		drawFloorOrnament(squareAspect[kDMSquareAspectFloorOrn], kDMViewFloorD3L);
1454 		break;
1455 	case kDMElementTypeDoorFront:
1456 		drawFloorOrnament(squareAspect[kDMSquareAspectFloorOrn], kDMViewFloorD3L);
1457 		drawObjectsCreaturesProjectilesExplosions(Thing(squareAspect[kDMSquareAspectFirstGroupOrObject]), dir, posX, posY, kDMViewSquareD3L, kDMCellOrderDoorPass1BackLeftBackRight);
1458 		drawWallSetBitmap(_bitmapWallSetDoorFrameLeftD3L, doorFrameLeftD3L);
1459 		drawDoor(squareAspect[kDMSquareAspectDoorThingIndex], (DoorState)squareAspect[kDMSquareAspectDoorState],
1460 					  _doorNativeBitmapIndexFrontD3LCR, getBitmapByteCount(48, 41), kDMDoorOrnamentD3LCR, &doorFrameD3L);
1461 		order = kDMCellOrderDoorPass2FrontLeftFrontRight;
1462 		break;
1463 	case kDMElementTypePit:
1464 		if (!squareAspect[kDMSquareAspectPitInvisible])
1465 			drawFloorPitOrStairsBitmap(kDMGraphicIdxFloorPitD3L, frameFloorPitD3L);
1466 		// fall through
1467 	case kDMElementTypeTeleporter:
1468 	case kDMElementTypeCorridor:
1469 		order = kDMCellOrderBackLeftBackRightFrontLeftFrontRight;
1470 		/* BUG0_64 Floor ornaments are drawn over open pits. There is no check to prevent drawing floor ornaments over open pits */
1471 		drawFloorOrnament(squareAspect[kDMSquareAspectFloorOrn], kDMViewFloorD3L);
1472 		break;
1473 	default:
1474 		skip = true;
1475 		break;
1476 	}
1477 
1478 	if (!skip)
1479 		drawObjectsCreaturesProjectilesExplosions(Thing(squareAspect[kDMSquareAspectFirstGroupOrObject]), dir, posX, posY, kDMViewSquareD3L, order);
1480 
1481 	if ((squareAspect[kDMSquareAspectElement] == kDMElementTypeTeleporter) && squareAspect[kDMSquareAspectTeleporterVisible])
1482 		drawField(&_fieldAspects188[kDMViewSquareD3L], _frameWalls163[kDMViewSquareD3L]._box);
1483 }
1484 
drawSquareD3R(Direction dir,int16 posX,int16 posY)1485 void DisplayMan::drawSquareD3R(Direction dir, int16 posX, int16 posY) {
1486 	static Frame doorFrameRightD3R = Frame(192, 223, 28, 70, 16, 43, 0, 0); // @ G0165_s_Graphic558_Frame_DoorFrameRight_D3R
1487 	static Frame frameStairsUpFrontD3R = Frame(149, 223, 25, 70, 40, 46, 5, 0); // @ G0112_s_Graphic558_Frame_StairsUpFront_D3R
1488 	static Frame frameStairsDownFrontD3R = Frame(149, 223, 28, 68, 40, 41, 5, 0); // @ G0123_s_Graphic558_Frame_StairsDownFront_D3R
1489 	static Frame frameFloorPitD3R = Frame(144, 223, 66, 73, 40, 8, 0, 0); // @ G0142_s_Graphic558_Frame_FloorPit_D3R
1490 	static DoorFrames doorFrameD3R = DoorFrames( // @ G0181_s_Graphic558_Frames_Door_D3R
1491 		/* { X1, X2, Y1, Y2, ByteWidth, Height, X, Y } */
1492 		Frame(150, 197, 28, 67, 24, 41, 0, 0),	/* Closed Or Destroyed */
1493 		Frame(150, 197, 28, 38, 24, 41, 0, 30),	/* Vertical Closed one fourth */
1494 		Frame(150, 197, 28, 48, 24, 41, 0, 20),	/* Vertical Closed half */
1495 		Frame(150, 197, 28, 58, 24, 41, 0, 10),	/* Vertical Closed three fourth */
1496 		Frame(150, 153, 28, 67, 24, 41, 18, 0),	/* Left Horizontal Closed one fourth */
1497 		Frame(150, 161, 28, 67, 24, 41, 12, 0),	/* Left Horizontal Closed half */
1498 		Frame(150, 167, 28, 67, 24, 41, 6, 0),	/* Left Horizontal Closed three fourth */
1499 		Frame(192, 197, 28, 67, 24, 41, 24, 0),	/* Right Horizontal Closed one fourth */
1500 		Frame(186, 197, 28, 67, 24, 41, 24, 0),	/* Right Horizontal Closed half */
1501 		Frame(180, 197, 28, 67, 24, 41, 24, 0)	/* Right Horizontal Closed three fourth */
1502 	);
1503 
1504 	CellOrder order = kDMCellOrderNone;
1505 	uint16 squareAspect[5];
1506 	bool skip = false;
1507 
1508 	_vm->_dungeonMan->setSquareAspect(squareAspect, dir, posX, posY);
1509 	switch (squareAspect[kDMSquareAspectElement]) {
1510 	case kDMElementTypeStairsFront:
1511 		if (squareAspect[kDMSquareAspectStairsUp])
1512 			drawFloorPitOrStairsBitmapFlippedHorizontally(_stairsNativeBitmapIndexUpFrontD3L, frameStairsUpFrontD3R);
1513 		else
1514 			drawFloorPitOrStairsBitmapFlippedHorizontally(_stairsNativeBitmapIndexDownFrontD3L, frameStairsDownFrontD3R);
1515 
1516 		order = kDMCellOrderBackRightBackLeftFrontRightFrontLeft;
1517 		/* BUG0_64 Floor ornaments are drawn over open pits. There is no check to prevent drawing floor ornaments over open pits */
1518 		drawFloorOrnament(squareAspect[kDMSquareAspectFloorOrn], kDMViewFloorD3R);
1519 		break;
1520 	case kDMElementTypeWall:
1521 		drawWallSetBitmap(_bitmapWallSetD3LCR, _frameWalls163[kDMViewSquareD3R]);
1522 		isDrawnWallOrnAnAlcove(squareAspect[kDMSquareAspectLeftWallOrnOrd], kDMViewWallD3RLeft);
1523 		if (isDrawnWallOrnAnAlcove(squareAspect[kDMSquareFrontWallOrnOrd], kDMViewWallD3RFront))
1524 			order = kDMCellOrderAlcove;
1525 		else
1526 			return;
1527 		break;
1528 	case kDMElementTypeDoorSide:
1529 	case kDMElementTypeStairsSide:
1530 		order = kDMCellOrderBackRightBackLeftFrontLeft;
1531 		/* BUG0_64 Floor ornaments are drawn over open pits. There is no check to prevent drawing floor ornaments over open pits */
1532 		drawFloorOrnament(squareAspect[kDMSquareAspectFloorOrn], kDMViewFloorD3R);
1533 		break;
1534 	case kDMElementTypeDoorFront:
1535 		drawFloorOrnament(squareAspect[kDMSquareAspectFloorOrn], kDMViewFloorD3R);
1536 		drawObjectsCreaturesProjectilesExplosions(Thing(squareAspect[kDMSquareAspectFirstGroupOrObject]), dir, posX, posY, kDMViewSquareD3R, kDMCellOrderDoorPass1BackRightBackLeft);
1537 		memmove(_tmpBitmap, _bitmapWallSetDoorFrameLeftD3L, 32 * 44);
1538 		drawDoorFrameBitmapFlippedHorizontally(_tmpBitmap, &doorFrameRightD3R);
1539 		if (((Door *)_vm->_dungeonMan->_thingData[kDMThingTypeDoor])[squareAspect[kDMSquareAspectDoorThingIndex]].hasButton())
1540 			drawDoorButton(_vm->indexToOrdinal(k0_DoorButton), kDMDoorButtonD3R);
1541 
1542 		drawDoor(squareAspect[kDMSquareAspectDoorThingIndex],
1543 					  (DoorState)squareAspect[kDMSquareAspectDoorState], _doorNativeBitmapIndexFrontD3LCR,
1544 					  getBitmapByteCount(48, 41), kDMDoorOrnamentD3LCR, &doorFrameD3R);
1545 		break;
1546 	case kDMElementTypePit:
1547 		if (!squareAspect[kDMSquareAspectPitInvisible])
1548 			drawFloorPitOrStairsBitmapFlippedHorizontally(kDMGraphicIdxFloorPitD3L, frameFloorPitD3R);
1549 		// fall through
1550 	case kDMElementTypeTeleporter:
1551 	case kDMElementTypeCorridor:
1552 		order = kDMCellOrderBackRightBackLeftFrontRightFrontLeft;
1553 		/* BUG0_64 Floor ornaments are drawn over open pits. There is no check to prevent drawing floor ornaments over open pits */
1554 		drawFloorOrnament(squareAspect[kDMSquareAspectFloorOrn], kDMViewFloorD3R);
1555 		break;
1556 	default:
1557 		skip = true;
1558 		break;
1559 	}
1560 
1561 	if (!skip)
1562 		drawObjectsCreaturesProjectilesExplosions(Thing(squareAspect[kDMSquareAspectFirstGroupOrObject]), dir, posX, posY, kDMViewSquareD3R, order);
1563 
1564 	if ((squareAspect[kDMSquareAspectElement] == kDMElementTypeTeleporter) && squareAspect[kDMSquareAspectTeleporterVisible])
1565 		drawField(&_fieldAspects188[kDMViewSquareD3R], _frameWalls163[kDMViewSquareD3R]._box);
1566 }
1567 
drawSquareD3C(Direction dir,int16 posX,int16 posY)1568 void DisplayMan::drawSquareD3C(Direction dir, int16 posX, int16 posY) {
1569 	static Frame doorFrameLeftD3C = Frame(64, 95, 27, 70, 16, 44, 0, 0); // @ G0166_s_Graphic558_Frame_DoorFrameLeft_D3C
1570 	static Frame doorFrameRightD3C = Frame(128, 159, 27, 70, 16, 44, 0, 0); // @ G0167_s_Graphic558_Frame_DoorFrameRight_D3C
1571 	static Frame frameStairsUpFrontD3C = Frame(64, 159, 25, 70, 48, 46, 0, 0); // @ G0111_s_Graphic558_Frame_StairsUpFront_D3C
1572 	static Frame frameStairsDownFrontD3C = Frame(64, 159, 28, 70, 48, 43, 0, 0); // @ G0122_s_Graphic558_Frame_StairsDownFront_D3C
1573 	static Frame frameFloorPitD3C = Frame(64, 159, 66, 73, 48, 8, 0, 0); // @ G0141_s_Graphic558_Frame_FloorPit_D3C
1574 	static DoorFrames doorFrameD3C = DoorFrames( // @ G0180_s_Graphic558_Frames_Door_D3C
1575 		/* { X1, X2, Y1, Y2, ByteWidth, Height, X, Y } */
1576 		Frame(88, 135, 28, 67, 24, 41, 0, 0),		/* Closed Or Destroyed */
1577 		Frame(88, 135, 28, 38, 24, 41, 0, 30),		/* Vertical Closed one fourth */
1578 		Frame(88, 135, 28, 48, 24, 41, 0, 20),		/* Vertical Closed half */
1579 		Frame(88, 135, 28, 58, 24, 41, 0, 10),		/* Vertical Closed three fourth */
1580 		Frame(88, 93, 28, 67, 24, 41, 18, 0),		/* Left Horizontal Closed one fourth */
1581 		Frame(88, 99, 28, 67, 24, 41, 12, 0),		/* Left Horizontal Closed half */
1582 		Frame(88, 105, 28, 67, 24, 41, 6, 0),		/* Left Horizontal Closed three fourth */
1583 		Frame(130, 135, 28, 67, 24, 41, 24, 0),		/* Right Horizontal Closed one fourth */
1584 		Frame(124, 135, 28, 67, 24, 41, 24, 0),		/* Right Horizontal Closed half */
1585 		Frame(118, 135, 28, 67, 24, 41, 24, 0)		/* Right Horizontal Closed three fourth */
1586 	);
1587 
1588 	uint16 squareAspect[5];
1589 	CellOrder order = kDMCellOrderNone;
1590 	bool skip = false;
1591 
1592 	DungeonMan &dungeon = *_vm->_dungeonMan;
1593 
1594 	dungeon.setSquareAspect(squareAspect, dir, posX, posY);
1595 	switch (squareAspect[kDMSquareAspectElement]) {
1596 	case kDMElementTypeStairsFront:
1597 		if (squareAspect[kDMSquareAspectStairsUp])
1598 			drawFloorPitOrStairsBitmap(_stairsNativeBitmapIndexUpFrontD3C, frameStairsUpFrontD3C);
1599 		else
1600 			drawFloorPitOrStairsBitmap(_stairsNativeBitmapIndexDownFrontD3C, frameStairsDownFrontD3C);
1601 
1602 		order = kDMCellOrderBackLeftBackRightFrontLeftFrontRight;
1603 		drawFloorOrnament(squareAspect[kDMSquareAspectFloorOrn], kDMViewFloorD3C); /* BUG0_64 Floor ornaments are drawn over open pits. There is no check to prevent drawing floor ornaments over open pits */
1604 		break;
1605 	case kDMElementTypeWall:
1606 		drawWallSetBitmapWithoutTransparency(_bitmapWallSetD3LCR, _frameWalls163[kDMViewSquareD3C]);
1607 		if (isDrawnWallOrnAnAlcove(squareAspect[kDMSquareFrontWallOrnOrd], kDMViewWallD3CFront))
1608 			order = kDMCellOrderAlcove;
1609 		else
1610 			return;
1611 
1612 		break;
1613 	case kDMElementTypeDoorFront:
1614 		drawFloorOrnament(squareAspect[kDMSquareAspectFloorOrn], kDMViewFloorD3C);
1615 		drawObjectsCreaturesProjectilesExplosions(Thing(squareAspect[kDMSquareAspectFirstGroupOrObject]), dir, posX, posY, kDMViewSquareD3C, kDMCellOrderDoorPass1BackLeftBackRight);
1616 		drawWallSetBitmap(_bitmapWallSetDoorFrameLeftD3C, doorFrameLeftD3C);
1617 		memmove(_tmpBitmap, _bitmapWallSetDoorFrameLeftD3C, 32 * 44);
1618 		drawDoorFrameBitmapFlippedHorizontally(_tmpBitmap, &doorFrameRightD3C);
1619 		if (((Door *)dungeon._thingData[kDMThingTypeDoor])[squareAspect[kDMSquareAspectDoorThingIndex]].hasButton())
1620 			drawDoorButton(_vm->indexToOrdinal(k0_DoorButton), kDMDoorButtonD3C);
1621 
1622 		drawDoor(squareAspect[kDMSquareAspectDoorThingIndex], (DoorState)squareAspect[kDMSquareAspectDoorState],
1623 					  _doorNativeBitmapIndexFrontD3LCR, getBitmapByteCount(48, 41), kDMDoorOrnamentD3LCR, &doorFrameD3C);
1624 		order = kDMCellOrderDoorPass2FrontLeftFrontRight;
1625 		break;
1626 	case kDMElementTypePit:
1627 		if (!squareAspect[kDMSquareAspectPitInvisible])
1628 			drawFloorPitOrStairsBitmap(kDMGraphicIdxFloorPitD3C, frameFloorPitD3C);
1629 		// fall through
1630 	case kDMElementTypeTeleporter:
1631 	case kDMElementTypeCorridor:
1632 		order = kDMCellOrderBackLeftBackRightFrontLeftFrontRight;
1633 		drawFloorOrnament(squareAspect[kDMSquareAspectFloorOrn], kDMViewFloorD3C); /* BUG0_64 Floor ornaments are drawn over open pits. There is no check to prevent drawing floor ornaments over open pits */
1634 		break;
1635 	default:
1636 		skip = true;
1637 		break;
1638 	}
1639 
1640 	if (!skip)
1641 		drawObjectsCreaturesProjectilesExplosions(Thing(squareAspect[kDMSquareAspectFirstGroupOrObject]), dir, posX, posY, kDMViewSquareD3C, order);
1642 
1643 	if ((squareAspect[kDMSquareAspectElement] == kDMElementTypeTeleporter) && squareAspect[kDMSquareAspectTeleporterVisible])
1644 		drawField(&_fieldAspects188[kDMViewSquareD3C], _frameWalls163[kDMViewSquareD3C]._box);
1645 }
1646 
drawSquareD2L(Direction dir,int16 posX,int16 posY)1647 void DisplayMan::drawSquareD2L(Direction dir, int16 posX, int16 posY) {
1648 	static Frame doorFrameTopD2L = Frame(0, 59, 22, 24, 48, 3, 16, 0); // @ G0173_s_Graphic558_Frame_DoorFrameTop_D2L
1649 	static Frame frameStairsUpFrontD2L = Frame(0, 63, 22, 83, 32, 62, 0, 0); // @ G0113_s_Graphic558_Frame_StairsUpFront_D2L
1650 	static Frame frameStairsDownFrontD2L = Frame(0, 63, 24, 85, 32, 62, 0, 0); // @ G0124_s_Graphic558_Frame_StairsDownFront_D2L
1651 	static Frame frameStairsSideD2L = Frame(60, 75, 57, 61, 8, 5, 0, 0); // @ G0132_s_Graphic558_Frame_StairsSide_D2L
1652 	static Frame frameFloorPitD2L = Frame(0, 79, 77, 88, 40, 12, 0, 0); // @ G0143_s_Graphic558_Frame_FloorPit_D2L
1653 	static Frame FrameCeilingPitD2L = Frame(0, 79, 19, 23, 40, 5, 0, 0); // @ G0152_s_Graphic558_Frame_CeilingPit_D2L
1654 	static DoorFrames doorFrameD2L = DoorFrames( // @ G0182_s_Graphic558_Frames_Door_D2L
1655 		/* { X1, X2, Y1, Y2, ByteWidth, Height, X, Y } */
1656 		Frame(0, 63, 24, 82, 32, 61, 0, 0),	   /* Closed Or Destroyed */
1657 		Frame(0, 63, 24, 39, 32, 61, 0, 45),   /* Vertical Closed one fourth */
1658 		Frame(0, 63, 24, 54, 32, 61, 0, 30),   /* Vertical Closed half */
1659 		Frame(0, 63, 24, 69, 32, 61, 0, 15),   /* Vertical Closed three fourth */
1660 		Frame(0, 7, 24, 82, 32, 61, 24, 0),    /* Left Horizontal Closed one fourth */
1661 		Frame(0, 15, 24, 82, 32, 61, 16, 0),   /* Left Horizontal Closed half */
1662 		Frame(0, 23, 24, 82, 32, 61, 8, 0),    /* Left Horizontal Closed three fourth */
1663 		Frame(56, 63, 24, 82, 32, 61, 32, 0),  /* Right Horizontal Closed one fourth */
1664 		Frame(48, 63, 24, 82, 32, 61, 32, 0),  /* Right Horizontal Closed half */
1665 		Frame(40, 63, 24, 82, 32, 61, 32, 0)   /* Right Horizontal Closed three fourth */
1666 	);
1667 
1668 	CellOrder order = kDMCellOrderNone;
1669 	uint16 squareAspect[5];
1670 	bool skip = false;
1671 
1672 	_vm->_dungeonMan->setSquareAspect(squareAspect, dir, posX, posY);
1673 	switch (squareAspect[kDMSquareAspectElement]) {
1674 	case kDMElementTypeStairsFront:
1675 		if (squareAspect[kDMSquareAspectStairsUp])
1676 			drawFloorPitOrStairsBitmap(_stairsNativeBitmapIndexUpFrontD2L, frameStairsUpFrontD2L);
1677 		else
1678 			drawFloorPitOrStairsBitmap(_stairsNativeBitmapIndexDownFrontD2L, frameStairsDownFrontD2L);
1679 
1680 		order = kDMCellOrderBackLeftBackRightFrontLeftFrontRight;
1681 		drawFloorOrnament(squareAspect[kDMSquareAspectFloorOrn], kDMViewFloorD2L); /* BUG0_64 Floor ornaments are drawn over open pits. There is no check to prevent drawing floor ornaments over open pits */
1682 		break;
1683 	case kDMElementTypeWall:
1684 		drawWallSetBitmap(_bitmapWallSetD2LCR, _frameWalls163[kDMViewSquareD2L]);
1685 		isDrawnWallOrnAnAlcove(squareAspect[kDMSquareAspectRightWallOrnOrd], kDMViewWallD2LRight);
1686 		if (isDrawnWallOrnAnAlcove(squareAspect[kDMSquareFrontWallOrnOrd], kDMViewWallD2LFront))
1687 			order = kDMCellOrderAlcove;
1688 		else
1689 			return;
1690 		break;
1691 	case kDMElementTypeStairsSide:
1692 		drawFloorPitOrStairsBitmap(_stairsNativeBitmapIndexSideD2L, frameStairsSideD2L);
1693 		// fall through
1694 	case kDMElementTypeDoorSide:
1695 		order = kDMCellOrderBackRightFrontLeftFrontRight;
1696 		drawFloorOrnament(squareAspect[kDMSquareAspectFloorOrn], kDMViewFloorD2L); /* BUG0_64 Floor ornaments are drawn over open pits. There is no check to prevent drawing floor ornaments over open pits */
1697 		break;
1698 	case kDMElementTypeDoorFront:
1699 		drawFloorOrnament(squareAspect[kDMSquareAspectFloorOrn], kDMViewFloorD2L);
1700 		drawObjectsCreaturesProjectilesExplosions(Thing(squareAspect[kDMSquareAspectFirstGroupOrObject]), dir, posX, posY, kDMViewSquareD2L, kDMCellOrderDoorPass1BackLeftBackRight);
1701 		drawWallSetBitmap(_bitmapWallSetDoorFrameTopD2LCR, doorFrameTopD2L);
1702 		drawDoor(squareAspect[kDMSquareAspectDoorThingIndex], (DoorState)squareAspect[kDMSquareAspectDoorState], _doorNativeBitmapIndexFrontD2LCR,
1703 					  getBitmapByteCount(64, 61), kDMDoorOrnamentD2LCR, &doorFrameD2L);
1704 		order = kDMCellOrderDoorPass2FrontLeftFrontRight;
1705 		break;
1706 	case kDMElementTypePit:
1707 		drawFloorPitOrStairsBitmap(squareAspect[kDMSquareAspectPitInvisible] ? kDMGraphicIdxFloorPitInvisibleD2L : kDMGraphicIdxFloorPitD2L,
1708 										frameFloorPitD2L);
1709 		// fall through
1710 	case kDMElementTypeTeleporter:
1711 	case kDMElementTypeCorridor:
1712 		order = kDMCellOrderBackLeftBackRightFrontLeftFrontRight;
1713 		drawFloorOrnament(squareAspect[kDMSquareAspectFloorOrn], kDMViewFloorD2L); /* BUG0_64 Floor ornaments are drawn over open pits. There is no check to prevent drawing floor ornaments over open pits */
1714 		break;
1715 
1716 	default:
1717 		skip = true;
1718 		break;
1719 	}
1720 
1721 	if (!skip) {
1722 		drawCeilingPit(kDMGraphicIdxCeilingPitD2L, &FrameCeilingPitD2L, posX, posY, false);
1723 		drawObjectsCreaturesProjectilesExplosions(Thing(squareAspect[kDMSquareAspectFirstGroupOrObject]), dir, posX, posY, kDMViewSquareD2L, order);
1724 	}
1725 
1726 	if ((squareAspect[kDMSquareAspectElement] == kDMElementTypeTeleporter) && squareAspect[kDMSquareAspectTeleporterVisible])
1727 		drawField(&_fieldAspects188[kDMViewSquareD2L], _frameWalls163[kDMViewSquareD2L]._box);
1728 }
1729 
drawSquareD2R(Direction dir,int16 posX,int16 posY)1730 void DisplayMan::drawSquareD2R(Direction dir, int16 posX, int16 posY) {
1731 	static Frame doorFrameTopD2R = Frame(164, 223, 22, 24, 48, 3, 16, 0); // @ G0175_s_Graphic558_Frame_DoorFrameTop_D2R
1732 	static Frame frameStairsUpFrontD2R = Frame(160, 223, 22, 83, 32, 62, 0, 0); // @ G0115_s_Graphic558_Frame_StairsUpFront_D2R
1733 	static Frame frameStairsDownFrontD2R = Frame(160, 223, 24, 85, 32, 62, 0, 0); // @ G0126_s_Graphic558_Frame_StairsDownFront_D2R
1734 	static Frame frameStairsSideD2R = Frame(148, 163, 57, 61, 8, 5, 0, 0); // @ G0133_s_Graphic558_Frame_StairsSide_D2R
1735 	static Frame frameFloorPitD2R = Frame(144, 223, 77, 88, 40, 12, 0, 0); // @ G0145_s_Graphic558_Frame_FloorPit_D2R
1736 	static Frame frameCeilingPitD2R = Frame(144, 223, 19, 23, 40, 5, 0, 0); // @ G0154_s_Graphic558_Frame_CeilingPit_D2R
1737 	static DoorFrames doorFrameD2R = DoorFrames( // @ G0184_s_Graphic558_Frames_Door_D2R
1738 		/* { X1, X2, Y1, Y2, ByteWidth, Height, X, Y } */
1739 		Frame(160, 223, 24, 82, 32, 61, 0, 0),	/* Closed Or Destroyed */
1740 		Frame(160, 223, 24, 39, 32, 61, 0, 45),	/* Vertical Closed one fourth */
1741 		Frame(160, 223, 24, 54, 32, 61, 0, 30),	/* Vertical Closed half */
1742 		Frame(160, 223, 24, 69, 32, 61, 0, 15),	/* Vertical Closed three fourth */
1743 		Frame(160, 167, 24, 82, 32, 61, 24, 0),	/* Left Horizontal Closed one fourth */
1744 		Frame(160, 175, 24, 82, 32, 61, 16, 0),	/* Left Horizontal Closed half */
1745 		Frame(160, 183, 24, 82, 32, 61, 8, 0),	/* Left Horizontal Closed three fourth */
1746 		Frame(216, 223, 24, 82, 32, 61, 32, 0),	/* Right Horizontal Closed one fourth */
1747 		Frame(208, 223, 24, 82, 32, 61, 32, 0),	/* Right Horizontal Closed half */
1748 		Frame(200, 223, 24, 82, 32, 61, 32, 0)  /* Right Horizontal Closed three fourth */
1749 	);
1750 
1751 	CellOrder order = kDMCellOrderNone;
1752 	uint16 squareAspect[5];
1753 	bool skip = false;
1754 
1755 	_vm->_dungeonMan->setSquareAspect(squareAspect, dir, posX, posY);
1756 	switch (squareAspect[kDMSquareAspectElement]) {
1757 	case kDMElementTypeStairsFront:
1758 		if (squareAspect[kDMSquareAspectStairsUp])
1759 			drawFloorPitOrStairsBitmapFlippedHorizontally(_stairsNativeBitmapIndexUpFrontD2L, frameStairsUpFrontD2R);
1760 		else
1761 			drawFloorPitOrStairsBitmapFlippedHorizontally(_stairsNativeBitmapIndexDownFrontD2L, frameStairsDownFrontD2R);
1762 
1763 		order = kDMCellOrderBackRightBackLeftFrontRightFrontLeft;
1764 		/* BUG0_64 Floor ornaments are drawn over open pits. There is no check to prevent drawing floor ornaments over open pits */
1765 		drawFloorOrnament(squareAspect[kDMSquareAspectFloorOrn], kDMViewFloorD2R);
1766 		drawCeilingPit(kDMGraphicIdxCeilingPitD2L, &frameCeilingPitD2R, posX, posY, true);
1767 		break;
1768 	case kDMElementTypeWall:
1769 		drawWallSetBitmap(_bitmapWallSetD2LCR, _frameWalls163[kDMViewSquareD2R]);
1770 		isDrawnWallOrnAnAlcove(squareAspect[kDMSquareAspectLeftWallOrnOrd], kDMViewWallD2RLeft);
1771 		if (isDrawnWallOrnAnAlcove(squareAspect[kDMSquareFrontWallOrnOrd], kDMViewWallD2RFront))
1772 			order = kDMCellOrderAlcove;
1773 		else
1774 			return;
1775 		break;
1776 	case kDMElementTypeStairsSide:
1777 		drawFloorPitOrStairsBitmapFlippedHorizontally(_stairsNativeBitmapIndexSideD2L, frameStairsSideD2R);
1778 		// fall through
1779 	case kDMElementTypeDoorSide:
1780 		order = kDMCellOrderBackLeftFrontRightFrontLeft;
1781 		/* BUG0_64 Floor ornaments are drawn over open pits. There is no check to prevent drawing floor ornaments over open pits */
1782 		drawFloorOrnament(squareAspect[kDMSquareAspectFloorOrn], kDMViewFloorD2R);
1783 		drawCeilingPit(kDMGraphicIdxCeilingPitD2L, &frameCeilingPitD2R, posX, posY, true);
1784 		break;
1785 	case kDMElementTypeDoorFront:
1786 		drawFloorOrnament(squareAspect[kDMSquareAspectFloorOrn], kDMViewFloorD2R);
1787 		drawObjectsCreaturesProjectilesExplosions(Thing(squareAspect[kDMSquareAspectFirstGroupOrObject]), dir, posX, posY, kDMViewSquareD2R, kDMCellOrderDoorPass1BackRightBackLeft);
1788 		drawWallSetBitmap(_bitmapWallSetDoorFrameTopD2LCR, doorFrameTopD2R);
1789 		drawDoor(squareAspect[kDMSquareAspectDoorThingIndex], (DoorState)squareAspect[kDMSquareAspectDoorState],
1790 					  _doorNativeBitmapIndexFrontD2LCR, getBitmapByteCount(64, 61), kDMDoorOrnamentD2LCR, &doorFrameD2R);
1791 		order = kDMCellOrderDoorPass2FrontRightFrontLeft;
1792 		break;
1793 	case kDMElementTypePit:
1794 		drawFloorPitOrStairsBitmapFlippedHorizontally(
1795 			squareAspect[kDMSquareAspectPitInvisible] ? kDMGraphicIdxFloorPitInvisibleD2L : kDMGraphicIdxFloorPitD2L, frameFloorPitD2R);
1796 		// fall through
1797 	case kDMElementTypeTeleporter:
1798 	case kDMElementTypeCorridor:
1799 		order = kDMCellOrderBackRightBackLeftFrontRightFrontLeft;
1800 		/* BUG0_64 Floor ornaments are drawn over open pits. There is no check to prevent drawing floor ornaments over open pits */
1801 		drawFloorOrnament(squareAspect[kDMSquareAspectFloorOrn], kDMViewFloorD2R);
1802 		drawCeilingPit(kDMGraphicIdxCeilingPitD2L, &frameCeilingPitD2R, posX, posY, true);
1803 		break;
1804 	default:
1805 		skip = true;
1806 		break;
1807 	}
1808 
1809 	if (!skip)
1810 		drawObjectsCreaturesProjectilesExplosions(Thing(squareAspect[kDMSquareAspectFirstGroupOrObject]), dir, posX, posY, kDMViewSquareD2R, order);
1811 
1812 	if ((squareAspect[kDMSquareAspectElement] == kDMElementTypeTeleporter) && squareAspect[kDMSquareAspectTeleporterVisible])
1813 		drawField(&_fieldAspects188[kDMViewSquareD2R], _frameWalls163[kDMViewSquareD2R]._box);
1814 }
1815 
drawSquareD2C(Direction dir,int16 posX,int16 posY)1816 void DisplayMan::drawSquareD2C(Direction dir, int16 posX, int16 posY) {
1817 	static Frame doorFrameLeftD2C = Frame(48, 95, 22, 86, 24, 65, 0, 0); // @ G0168_s_Graphic558_Frame_DoorFrameLeft_D2C
1818 	static Frame doorFrameRightD2C = Frame(128, 175, 22, 86, 24, 65, 0, 0); // @ G0169_s_Graphic558_Frame_DoorFrameRight_D2C
1819 	static Frame doorFrameTopD2C = Frame(64, 159, 22, 24, 48, 3, 0, 0); // @ G0174_s_Graphic558_Frame_DoorFrameTop_D2C
1820 	static Frame frameStairsUpFrontD2C = Frame(64, 159, 22, 83, 48, 62, 0, 0); // @ G0114_s_Graphic558_Frame_StairsUpFront_D2C
1821 	static Frame frameStairsDownFrontD2C = Frame(64, 159, 24, 85, 48, 62, 0, 0); // @ G0125_s_Graphic558_Frame_StairsDownFront_D2C
1822 	static Frame frameFloorPitD2C = Frame(64, 159, 77, 88, 48, 12, 0, 0); // @ G0144_s_Graphic558_Frame_FloorPit_D2C
1823 	static Frame frameCeilingPitD2C = Frame(64, 159, 19, 23, 48, 5, 0, 0); // @ G0153_s_Graphic558_Frame_CeilingPit_D2C
1824 	static DoorFrames doorFrameD2C = DoorFrames( // @ G0183_s_Graphic558_Frames_Door_D2C
1825 		/* { X1, X2, Y1, Y2, ByteWidth, Height, X, Y } */
1826 		Frame(80, 143, 24, 82, 32, 61, 0, 0),    /* Closed Or Destroyed */
1827 		Frame(80, 143, 24, 39, 32, 61, 0, 45),   /* Vertical Closed one fourth */
1828 		Frame(80, 143, 24, 54, 32, 61, 0, 30),   /* Vertical Closed half */
1829 		Frame(80, 143, 24, 69, 32, 61, 0, 15),   /* Vertical Closed three fourth */
1830 		Frame(80, 87, 24, 82, 32, 61, 24, 0),    /* Left Horizontal Closed one fourth */
1831 		Frame(80, 95, 24, 82, 32, 61, 16, 0),    /* Left Horizontal Closed half */
1832 		Frame(80, 103, 24, 82, 32, 61, 8, 0),    /* Left Horizontal Closed three fourth */
1833 		Frame(136, 143, 24, 82, 32, 61, 32, 0),  /* Right Horizontal Closed one fourth */
1834 		Frame(128, 143, 24, 82, 32, 61, 32, 0),  /* Right Horizontal Closed half */
1835 		Frame(120, 143, 24, 82, 32, 61, 32, 0)   /* Right Horizontal Closed three fourth */
1836 	);
1837 
1838 	CellOrder order = kDMCellOrderNone;
1839 	uint16 squareAspect[5];
1840 	bool skip = false;
1841 
1842 	DungeonMan &dungeon = *_vm->_dungeonMan;
1843 	dungeon.setSquareAspect(squareAspect, dir, posX, posY);
1844 	switch (squareAspect[kDMSquareAspectElement]) {
1845 	case kDMElementTypeStairsFront:
1846 		if (squareAspect[kDMSquareAspectStairsUp])
1847 			drawFloorPitOrStairsBitmap(_stairsNativeBitmapIndexUpFrontD2C, frameStairsUpFrontD2C);
1848 		else
1849 			drawFloorPitOrStairsBitmap(_stairsNativeBitmapIndexDownFrontD2C, frameStairsDownFrontD2C);
1850 
1851 		order = kDMCellOrderBackLeftBackRightFrontLeftFrontRight;
1852 		/* BUG0_64 Floor ornaments are drawn over open pits. There is no check to prevent drawing floor ornaments over open pits */
1853 		drawFloorOrnament(squareAspect[kDMSquareAspectFloorOrn], kDMViewFloorD2C);
1854 		drawCeilingPit(kDMGraphicIdxCeilingPitD2C, &frameCeilingPitD2C, posX, posY, false);
1855 		break;
1856 	case kDMElementTypeWall:
1857 		drawWallSetBitmapWithoutTransparency(_bitmapWallSetD2LCR, _frameWalls163[kDMViewSquareD2C]);
1858 		if (isDrawnWallOrnAnAlcove(squareAspect[kDMSquareFrontWallOrnOrd], kDMViewWallD2CFront))
1859 			order = kDMCellOrderAlcove;
1860 		else
1861 			return;
1862 		break;
1863 	case kDMElementTypeDoorFront:
1864 		drawFloorOrnament(squareAspect[kDMSquareAspectFloorOrn], kDMViewFloorD2C);
1865 		drawObjectsCreaturesProjectilesExplosions(Thing(squareAspect[kDMSquareAspectFirstGroupOrObject]), dir, posX, posY, kDMViewSquareD2C, kDMCellOrderDoorPass1BackLeftBackRight);
1866 		drawWallSetBitmap(_bitmapWallSetDoorFrameTopD2LCR, doorFrameTopD2C);
1867 		drawWallSetBitmap(_bitmapWallSetDoorFrameLeftD2C, doorFrameLeftD2C);
1868 		memcpy(_tmpBitmap, _bitmapWallSetDoorFrameLeftD2C, 48 * 65);
1869 		drawDoorFrameBitmapFlippedHorizontally(_tmpBitmap, &doorFrameRightD2C);
1870 		if (((Door *)dungeon._thingData[kDMThingTypeDoor])[squareAspect[kDMSquareAspectDoorThingIndex]].hasButton())
1871 			drawDoorButton(_vm->indexToOrdinal(k0_DoorButton), kDMDoorButtonD2C);
1872 
1873 		drawDoor(squareAspect[kDMSquareAspectDoorThingIndex], (DoorState)squareAspect[kDMSquareAspectDoorState],
1874 					  _doorNativeBitmapIndexFrontD2LCR, getBitmapByteCount(64, 61), kDMDoorOrnamentD2LCR, &doorFrameD2C);
1875 		order = kDMCellOrderDoorPass2FrontLeftFrontRight;
1876 		break;
1877 	case kDMElementTypePit:
1878 		drawFloorPitOrStairsBitmap(squareAspect[kDMSquareAspectPitInvisible] ? kDMGraphicIdxFloorPitInvisibleD2C : kDMGraphicIdxFloorPitD2C, frameFloorPitD2C);
1879 		// fall through
1880 	case kDMElementTypeTeleporter:
1881 	case kDMElementTypeCorridor:
1882 		order = kDMCellOrderBackLeftBackRightFrontLeftFrontRight;
1883 		/* BUG0_64 Floor ornaments are drawn over open pits. There is no check to prevent drawing floor ornaments over open pits */
1884 		drawFloorOrnament(squareAspect[kDMSquareAspectFloorOrn], kDMViewFloorD2C);
1885 		drawCeilingPit(kDMGraphicIdxCeilingPitD2C, &frameCeilingPitD2C, posX, posY, false);
1886 		break;
1887 	default:
1888 		skip = true;
1889 		break;
1890 	}
1891 
1892 	if (!skip)
1893 		drawObjectsCreaturesProjectilesExplosions(Thing(squareAspect[kDMSquareAspectFirstGroupOrObject]), dir, posX, posY, kDMViewSquareD2C, order);
1894 
1895 	if ((squareAspect[kDMSquareAspectElement] == kDMElementTypeTeleporter) && squareAspect[kDMSquareAspectTeleporterVisible])
1896 		drawField(&_fieldAspects188[kDMViewSquareD2C], _frameWalls163[kDMViewSquareD2C]._box);
1897 }
1898 
drawSquareD1L(Direction dir,int16 posX,int16 posY)1899 void DisplayMan::drawSquareD1L(Direction dir, int16 posX, int16 posY) {
1900 	static Frame doorFrameTopD1L = Frame(0, 31, 14, 17, 64, 4, 16, 0); // @ G0176_s_Graphic558_Frame_DoorFrameTop_D1L
1901 	static Frame frameStairsUpFrontD1L = Frame(0, 31, 9, 108, 16, 100, 0, 0); // @ G0116_s_Graphic558_Frame_StairsUpFront_D1L
1902 	static Frame frameStairsDownFrontD1L = Frame(0, 31, 18, 108, 16, 91, 0, 0); // @ G0127_s_Graphic558_Frame_StairsDownFront_D1L
1903 	static Frame frameStairsUpSideD1L = Frame(32, 63, 57, 99, 16, 43, 0, 0); // @ G0134_s_Graphic558_Frame_StairsUpSide_D1L
1904 	static Frame frameStairsDownSideD1L = Frame(32, 63, 60, 98, 16, 39, 0, 0); // @ G0136_s_Graphic558_Frame_StairsDownSide_D1L
1905 	static Frame frameFloorPitD1L = Frame(0, 63, 93, 116, 32, 24, 0, 0); // @ G0146_s_Graphic558_Frame_FloorPit_D1L
1906 	static Frame frameCeilingPitD1L = Frame(0, 63, 8, 16, 32, 9, 0, 0); // @ G0155_s_Graphic558_Frame_CeilingPit_D1L
1907 	static DoorFrames doorFrameD1L = DoorFrames( // @ G0185_s_Graphic558_Frames_Door_D1L
1908 		/* { X1, X2, Y1, Y2, ByteWidth, Height, X, Y } */
1909 		Frame(0, 31, 17, 102, 48, 88, 64, 0),   /* Closed Or Destroyed */
1910 		Frame(0, 31, 17, 38, 48, 88, 64, 66),   /* Vertical Closed one fourth */
1911 		Frame(0, 31, 17, 60, 48, 88, 64, 44),   /* Vertical Closed half */
1912 		Frame(0, 31, 17, 82, 48, 88, 64, 22),   /* Vertical Closed three fourth */
1913 		Frame(0, 0, 0, 0, 0, 0, 0, 0),          /* Left Horizontal Closed one fourth */
1914 		Frame(0, 0, 0, 0, 0, 0, 0, 0),          /* Left Horizontal Closed half */
1915 		Frame(0, 0, 0, 0, 0, 0, 0, 0),          /* Left Horizontal Closed three fourth */
1916 		Frame(20, 31, 17, 102, 48, 88, 48, 0),  /* Right Horizontal Closed one fourth */
1917 		Frame(8, 31, 17, 102, 48, 88, 48, 0),   /* Right Horizontal Closed half */
1918 		Frame(0, 31, 17, 102, 48, 88, 52, 0)    /* Right Horizontal Closed three fourth */
1919 	);
1920 
1921 	CellOrder order = kDMCellOrderNone;
1922 	uint16 squareAspect[5];
1923 	bool skip = false;
1924 
1925 	_vm->_dungeonMan->setSquareAspect(squareAspect, dir, posX, posY);
1926 	switch (squareAspect[kDMSquareAspectElement]) {
1927 	case kDMElementTypeStairsFront:
1928 		if (squareAspect[kDMSquareAspectStairsUp])
1929 			drawFloorPitOrStairsBitmap(_stairsNativeBitmapIndexUpFrontD1L, frameStairsUpFrontD1L);
1930 		else
1931 			drawFloorPitOrStairsBitmap(_stairsNativeBitmapIndexDownFrontD1L, frameStairsDownFrontD1L);
1932 
1933 		order = kDMCellOrderBackRightFrontRight;
1934 		/* BUG0_64 Floor ornaments are drawn over open pits. There is no check to prevent drawing floor ornaments over open pits */
1935 		drawFloorOrnament(squareAspect[kDMSquareAspectFloorOrn], kDMViewFloorD1L);
1936 		drawCeilingPit(kDMGraphicIdxCeilingPitD1L, &frameCeilingPitD1L, posX, posY, false);
1937 		break;
1938 	case kDMElementTypeWall:
1939 		drawWallSetBitmap(_bitmapWallSetD1LCR, _frameWalls163[kDMViewSquareD1L]);
1940 		isDrawnWallOrnAnAlcove(squareAspect[kDMSquareAspectRightWallOrnOrd], kDMViewWallD1LRight);
1941 		return;
1942 	case kDMElementTypeStairsSide:
1943 		if (squareAspect[kDMSquareAspectStairsUp])
1944 			drawFloorPitOrStairsBitmap(_stairsNativeBitmapIndexUpSideD1L, frameStairsUpSideD1L);
1945 		else
1946 			drawFloorPitOrStairsBitmap(_stairsNativeBitmapIndexDownSideD1L, frameStairsDownSideD1L);
1947 		// fall through
1948 	case kDMElementTypeDoorSide:
1949 		order = kDMCellOrderBackRightFrontRight;
1950 		/* BUG0_64 Floor ornaments are drawn over open pits. There is no check to prevent drawing floor ornaments over open pits */
1951 		drawFloorOrnament(squareAspect[kDMSquareAspectFloorOrn], kDMViewFloorD1L);
1952 		drawCeilingPit(kDMGraphicIdxCeilingPitD1L, &frameCeilingPitD1L, posX, posY, false);
1953 		break;
1954 	case kDMElementTypeDoorFront:
1955 		drawFloorOrnament(squareAspect[kDMSquareAspectFloorOrn], kDMViewFloorD1L);
1956 		drawObjectsCreaturesProjectilesExplosions(Thing(squareAspect[kDMSquareAspectFirstGroupOrObject]), dir, posX, posY, kDMViewSquareD1L, kDMCellOrderDoorPass1BackRight);
1957 		drawWallSetBitmap(_bitmapWallSetDoorFrameTopD1LCR, doorFrameTopD1L);
1958 		drawDoor(squareAspect[kDMSquareAspectDoorThingIndex], (DoorState)squareAspect[kDMSquareAspectDoorState],
1959 					  _doorNativeBitmapIndexFrontD1LCR, getBitmapByteCount(96, 88), kDMDoorOrnamentD1LCR, &doorFrameD1L);
1960 		order = kDMCellOrderDoorPass2FrontRight;
1961 		break;
1962 	case kDMElementTypePit:
1963 		drawFloorPitOrStairsBitmap(squareAspect[kDMSquareAspectPitInvisible] ? kDMGraphicIdxFloorPitInvisibleD1L : kDMGraphicIdxFloorPitD1L, frameFloorPitD1L);
1964 		// fall through
1965 	case kDMElementTypeTeleporter:
1966 	case kDMElementTypeCorridor:
1967 		order = kDMCellOrderBackRightFrontRight;
1968 		 /* BUG0_64 Floor ornaments are drawn over open pits. There is no check to prevent drawing floor ornaments over open pits */
1969 		drawFloorOrnament(squareAspect[kDMSquareAspectFloorOrn], kDMViewFloorD1L);
1970 		drawCeilingPit(kDMGraphicIdxCeilingPitD1L, &frameCeilingPitD1L, posX, posY, false);
1971 		break;
1972 	default:
1973 		skip = true;
1974 		break;
1975 	}
1976 
1977 	if (!skip)
1978 		drawObjectsCreaturesProjectilesExplosions(Thing(squareAspect[kDMSquareAspectFirstGroupOrObject]), dir, posX, posY, kDMViewSquareD1L, order);
1979 
1980 	if ((squareAspect[kDMSquareAspectElement] == kDMElementTypeTeleporter) && squareAspect[kDMSquareAspectTeleporterVisible])
1981 		drawField(&_fieldAspects188[kDMViewSquareD1L], _frameWalls163[kDMViewSquareD1L]._box);
1982 }
1983 
drawSquareD1R(Direction dir,int16 posX,int16 posY)1984 void DisplayMan::drawSquareD1R(Direction dir, int16 posX, int16 posY) {
1985 	static Frame doorFrameTopD1R = Frame(192, 223, 14, 17, 64, 4, 16, 0); // @ G0178_s_Graphic558_Frame_DoorFrameTop_D1R
1986 	static Frame frameStairsUpFrontD1R = Frame(192, 223, 9, 108, 16, 100, 0, 0); // @ G0118_s_Graphic558_Frame_StairsUpFront_D1R
1987 	static Frame frameStairsDownFrontD1R = Frame(192, 223, 18, 108, 16, 91, 0, 0); // @ G0129_s_Graphic558_Frame_StairsDownFront_D1R
1988 	static Frame frameStairsUpSideD1R = Frame(160, 191, 57, 99, 16, 43, 0, 0); // @ G0135_s_Graphic558_Frame_StairsUpSide_D1R
1989 	static Frame frameStairsDownSideD1R = Frame(160, 191, 60, 98, 16, 39, 0, 0); // @ G0137_s_Graphic558_Frame_StairsDownSide_D1R
1990 	static Frame frameFloorPitD1R = Frame(160, 223, 93, 116, 32, 24, 0, 0); // @ G0148_s_Graphic558_Frame_FloorPit_D1R
1991 	static Frame frameCeilingPitD1R = Frame(160, 223, 8, 16, 32, 9, 0, 0); // @ G0157_s_Graphic558_Frame_CeilingPit_D1R
1992 	static DoorFrames doorFrameD1R = DoorFrames( // @ G0187_s_Graphic558_Frames_Door_D1R
1993 		/* { X1, X2, Y1, Y2, ByteWidth, Height, X, Y } */
1994 		Frame(192, 223, 17, 102, 48, 88, 0, 0),   /* Closed Or Destroyed */
1995 		Frame(192, 223, 17, 38, 48, 88, 0, 66),   /* Vertical Closed one fourth */
1996 		Frame(192, 223, 17, 60, 48, 88, 0, 44),   /* Vertical Closed half */
1997 		Frame(192, 223, 17, 82, 48, 88, 0, 22),   /* Vertical Closed three fourth */
1998 		Frame(192, 203, 17, 102, 48, 88, 36, 0),  /* Left Horizontal Closed one fourth */
1999 		Frame(192, 215, 17, 102, 48, 88, 24, 0),  /* Left Horizontal Closed half */
2000 		Frame(192, 223, 17, 102, 48, 88, 12, 0),  /* Left Horizontal Closed three fourth */
2001 		Frame(0, 0, 0, 0, 0, 0, 0, 0),            /* Right Horizontal Closed one fourth */
2002 		Frame(0, 0, 0, 0, 0, 0, 0, 0),            /* Right Horizontal Closed half */
2003 		Frame(0, 0, 0, 0, 0, 0, 0, 0)             /* Right Horizontal Closed three fourth */
2004 	);
2005 
2006 	CellOrder order = kDMCellOrderNone;
2007 	uint16 squareAspect[5];
2008 	bool skip = false;
2009 
2010 	_vm->_dungeonMan->setSquareAspect(squareAspect, dir, posX, posY);
2011 	switch (squareAspect[kDMSquareAspectElement]) {
2012 	case kDMElementTypeStairsFront:
2013 		if (squareAspect[kDMSquareAspectStairsUp])
2014 			drawFloorPitOrStairsBitmapFlippedHorizontally(_stairsNativeBitmapIndexUpFrontD1L, frameStairsUpFrontD1R);
2015 		else
2016 			drawFloorPitOrStairsBitmapFlippedHorizontally(_stairsNativeBitmapIndexDownFrontD1L, frameStairsDownFrontD1R);
2017 
2018 		order = kDMCellOrderBackLeftFrontLeft;
2019 		drawFloorOrnament(squareAspect[kDMSquareAspectFloorOrn], kDMViewFloorD1R); /* BUG0_64 Floor ornaments are drawn over open pits. There is no check to prevent drawing floor ornaments over open pits */
2020 		drawCeilingPit(kDMGraphicIdxCeilingPitD1L, &frameCeilingPitD1R, posX, posY, true);
2021 		break;
2022 	case kDMElementTypeWall:
2023 		drawWallSetBitmap(_bitmapWallSetD1LCR, _frameWalls163[kDMViewSquareD1R]);
2024 		isDrawnWallOrnAnAlcove(squareAspect[kDMSquareAspectLeftWallOrnOrd], kDMViewWallD1RLeft);
2025 		return;
2026 	case kDMElementTypeStairsSide:
2027 		if (squareAspect[kDMSquareAspectStairsUp])
2028 			drawFloorPitOrStairsBitmapFlippedHorizontally(_stairsNativeBitmapIndexUpSideD1L, frameStairsUpSideD1R);
2029 		else
2030 			drawFloorPitOrStairsBitmapFlippedHorizontally(_stairsNativeBitmapIndexDownSideD1L, frameStairsDownSideD1R);
2031 
2032 		// fall through
2033 	case kDMElementTypeDoorSide:
2034 		order = kDMCellOrderBackLeftFrontLeft;
2035 		drawFloorOrnament(squareAspect[kDMSquareAspectFloorOrn], kDMViewFloorD1R); /* BUG0_64 Floor ornaments are drawn over open pits. There is no check to prevent drawing floor ornaments over open pits */
2036 		drawCeilingPit(kDMGraphicIdxCeilingPitD1L, &frameCeilingPitD1R, posX, posY, true);
2037 		break;
2038 	case kDMElementTypeDoorFront:
2039 		drawFloorOrnament(squareAspect[kDMSquareAspectFloorOrn], kDMViewFloorD1R);
2040 		drawObjectsCreaturesProjectilesExplosions(Thing(squareAspect[kDMSquareAspectFirstGroupOrObject]), dir, posX, posY, kDMViewSquareD1R, kDMCellOrderDoorPass1BackLeft);
2041 		drawWallSetBitmap(_bitmapWallSetDoorFrameTopD1LCR, doorFrameTopD1R);
2042 		drawDoor(squareAspect[kDMSquareAspectDoorThingIndex], (DoorState)squareAspect[kDMSquareAspectDoorState],
2043 					  _doorNativeBitmapIndexFrontD1LCR, getBitmapByteCount(96, 88), kDMDoorOrnamentD1LCR, &doorFrameD1R);
2044 		order = kDMCellOrderDoorPass2FrontLeft;
2045 		break;
2046 	case kDMElementTypePit:
2047 		drawFloorPitOrStairsBitmapFlippedHorizontally(squareAspect[kDMSquareAspectPitInvisible] ? kDMGraphicIdxFloorPitInvisibleD1L
2048 														   : kDMGraphicIdxFloorPitD1L, frameFloorPitD1R);
2049 		// fall through
2050 	case kDMElementTypeTeleporter:
2051 	case kDMElementTypeCorridor:
2052 		order = kDMCellOrderBackLeftFrontLeft;
2053 		drawFloorOrnament(squareAspect[kDMSquareAspectFloorOrn], kDMViewFloorD1R); /* BUG0_64 Floor ornaments are drawn over open pits. There is no check to prevent drawing floor ornaments over open pits */
2054 		drawCeilingPit(kDMGraphicIdxCeilingPitD1L, &frameCeilingPitD1R, posX, posY, true);
2055 		break;
2056 	default:
2057 		skip = true;
2058 		break;
2059 	}
2060 
2061 	if (!skip)
2062 		drawObjectsCreaturesProjectilesExplosions(Thing(squareAspect[kDMSquareAspectFirstGroupOrObject]), dir, posX, posY, kDMViewSquareD1R, order);
2063 
2064 	if ((squareAspect[kDMSquareAspectElement] == kDMElementTypeTeleporter) && squareAspect[kDMSquareAspectTeleporterVisible])
2065 		drawField(&_fieldAspects188[kDMViewSquareD1R], _frameWalls163[kDMViewSquareD1R]._box);
2066 }
2067 
drawSquareD1C(Direction dir,int16 posX,int16 posY)2068 void DisplayMan::drawSquareD1C(Direction dir, int16 posX, int16 posY) {
2069 	static Frame doorFrameTopD1C = Frame(48, 175, 14, 17, 64, 4, 0, 0); // @ G0177_s_Graphic558_Frame_DoorFrameTop_D1C
2070 	static Frame frameStairsUpFrontD1C = Frame(32, 191, 9, 108, 80, 100, 0, 0); // @ G0117_s_Graphic558_Frame_StairsUpFront_D1C
2071 	static Frame frameStairsDownFrontD1C = Frame(32, 191, 18, 108, 80, 91, 0, 0); // @ G0128_s_Graphic558_Frame_StairsDownFront_D1C
2072 	static Frame frameFloorPitD1C = Frame(32, 191, 93, 116, 80, 24, 0, 0); // @ G0147_s_Graphic558_Frame_FloorPit_D1C
2073 	static Frame frameCeilingPitD1C = Frame(32, 191, 8, 16, 80, 9, 0, 0); // @ G0156_s_Graphic558_Frame_CeilingPit_D1C
2074 	static Box boxThievesEyeVisibleArea(0, 95, 0, 94); // @ G0107_s_Graphic558_Box_ThievesEye_VisibleArea
2075 
2076 	ChampionMan &championMan = *_vm->_championMan;
2077 
2078 	CellOrder order = kDMCellOrderNone;
2079 	uint16 squareAspect[5];
2080 	bool skip = false;
2081 
2082 	DungeonMan &dungeon = *_vm->_dungeonMan;
2083 
2084 	dungeon.setSquareAspect(squareAspect, dir, posX, posY);
2085 	switch (dungeon._squareAheadElement = (ElementType)squareAspect[kDMSquareAspectElement]) {
2086 	case kDMElementTypeStairsFront:
2087 		if (squareAspect[kDMSquareAspectStairsUp])
2088 			drawFloorPitOrStairsBitmap(_stairsNativeBitmapIndexUpFrontD1C, frameStairsUpFrontD1C);
2089 		else
2090 			drawFloorPitOrStairsBitmap(_stairsNativeBitmapIndexDownFrontD1C, frameStairsDownFrontD1C);
2091 
2092 		order = kDMCellOrderBackLeftBackRightFrontLeftFrontRight;
2093 		/* BUG0_64 Floor ornaments are drawn over open pits. There is no check to prevent drawing floor ornaments over open pits */
2094 		drawFloorOrnament(squareAspect[kDMSquareAspectFloorOrn], kDMViewFloorD1C);
2095 		drawCeilingPit(kDMGraphicIdxCeilingPitD1C, &frameCeilingPitD1C, posX, posY, false);
2096 		break;
2097 	case kDMElementTypeWall:
2098 		dungeon._isFacingAlcove = false;
2099 		dungeon._isFacingViAltar = false;
2100 		dungeon._isFacingFountain = false;
2101 		if (championMan._party._event73Count_ThievesEye) {
2102 			isDerivedBitmapInCache(kDMDerivedBitmapThievesEyeVisibleArea);
2103 			blitToBitmap(_bitmapViewport, getDerivedBitmap(kDMDerivedBitmapThievesEyeVisibleArea),
2104 							  boxThievesEyeVisibleArea, _boxThievesEyeViewPortVisibleArea._rect.left, _boxThievesEyeViewPortVisibleArea._rect.top,
2105 							  k112_byteWidthViewport, 48, kDMColorNoTransparency, 136, 95);
2106 			byte *bitmap = getNativeBitmapOrGraphic(kDMGraphicIdxHoleInWall);
2107 			blitToBitmap(bitmap, getDerivedBitmap(kDMDerivedBitmapThievesEyeVisibleArea),
2108 							  boxThievesEyeVisibleArea, 0, 0, 48, 48, kDMColorFlesh, 95, 95);
2109 		}
2110 		drawWallSetBitmapWithoutTransparency(_bitmapWallSetD1LCR, _frameWalls163[kDMViewSquareD1C]);
2111 		if (isDrawnWallOrnAnAlcove(squareAspect[kDMSquareFrontWallOrnOrd], kDMViewWallD1CFront))
2112 			drawObjectsCreaturesProjectilesExplosions(Thing(squareAspect[kDMSquareAspectFirstGroupOrObject]), dir, posX, posY, kDMViewSquareD1C, kDMCellOrderAlcove);
2113 
2114 		if (championMan._party._event73Count_ThievesEye) {
2115 			blitToBitmap(getDerivedBitmap(kDMDerivedBitmapThievesEyeVisibleArea),
2116 							  _bitmapViewport, _boxThievesEyeViewPortVisibleArea, 0, 0,
2117 							  48, k112_byteWidthViewport, kDMColorGold, 95, k136_heightViewport); /* BUG0_74 */
2118 			addDerivedBitmap(kDMDerivedBitmapThievesEyeVisibleArea);
2119 			releaseBlock(kDMDerivedBitmapThievesEyeVisibleArea | 0x8000);
2120 		}
2121 		return;
2122 	case kDMElementTypeDoorFront:
2123 		drawFloorOrnament(squareAspect[kDMSquareAspectFloorOrn], kDMViewFloorD1C);
2124 		drawObjectsCreaturesProjectilesExplosions(Thing(squareAspect[kDMSquareAspectFirstGroupOrObject]), dir, posX, posY, kDMViewSquareD1C, kDMCellOrderDoorPass1BackLeftBackRight);
2125 		drawWallSetBitmap(_bitmapWallSetDoorFrameTopD1LCR, doorFrameTopD1C);
2126 		drawWallSetBitmap(_bitmapWallSetDoorFrameLeftD1C, _doorFrameLeftD1C);
2127 		drawWallSetBitmap(_bitmapWallSetDoorFrameRightD1C, _doorFrameRightD1C);
2128 		if (((Door *)dungeon._thingData[kDMThingTypeDoor])[squareAspect[kDMSquareAspectDoorThingIndex]].hasButton())
2129 			drawDoorButton(_vm->indexToOrdinal(k0_DoorButton), kDMDoorButtonD1C);
2130 
2131 		drawDoor(squareAspect[kDMSquareAspectDoorThingIndex], (DoorState)squareAspect[kDMSquareAspectDoorState],
2132 					  _doorNativeBitmapIndexFrontD1LCR, getBitmapByteCount(96, 88), kDMDoorOrnamentD1LCR, _doorFrameD1C);
2133 		order = kDMCellOrderDoorPass2FrontLeftFrontRight;
2134 		break;
2135 	case kDMElementTypePit:
2136 		drawFloorPitOrStairsBitmap(squareAspect[kDMSquareAspectPitInvisible] ? kDMGraphicIdxFloorPitInvisibleD1C : kDMGraphicIdxFloorPitD1C, frameFloorPitD1C);
2137 		// fall through
2138 	case kDMElementTypeTeleporter:
2139 	case kDMElementTypeCorridor:
2140 		order = kDMCellOrderBackLeftBackRightFrontLeftFrontRight;
2141 		/* BUG0_64 Floor ornaments are drawn over open pits. There is no check to prevent drawing floor ornaments over open pits */
2142 		drawFloorOrnament(squareAspect[kDMSquareAspectFloorOrn], kDMViewFloorD1C);
2143 		drawCeilingPit(kDMGraphicIdxCeilingPitD1C, &frameCeilingPitD1C, posX, posY, false);
2144 		break;
2145 	default:
2146 		skip = true;
2147 		break;
2148 	}
2149 
2150 	if (!skip)
2151 		drawObjectsCreaturesProjectilesExplosions(Thing(squareAspect[kDMSquareAspectFirstGroupOrObject]), dir, posX, posY, kDMViewSquareD1C, order);
2152 
2153 	if ((squareAspect[kDMSquareAspectElement] == kDMElementTypeTeleporter) && squareAspect[kDMSquareAspectTeleporterVisible])
2154 		drawField(&_fieldAspects188[kDMViewSquareD1C], _frameWalls163[kDMViewSquareD1C]._box);
2155 }
2156 
drawSquareD0L(Direction dir,int16 posX,int16 posY)2157 void DisplayMan::drawSquareD0L(Direction dir, int16 posX, int16 posY) {
2158 	static Frame frameStairsSideD0L = Frame(0, 15, 73, 85, 8, 13, 0, 0); // @ G0138_s_Graphic558_Frame_StairsSide_D0L
2159 	static Frame frameFloorPitD0L = Frame(0, 31, 124, 135, 16, 12, 0, 0); // @ G0149_s_Graphic558_Frame_FloorPit_D0L
2160 	static Frame frameCeilingPitD0L = Frame(0, 15, 0, 3, 8, 4, 0, 0); // @ G0158_s_Graphic558_Frame_CeilingPit_D0L
2161 
2162 	uint16 squareAspect[5];
2163 	_vm->_dungeonMan->setSquareAspect(squareAspect, dir, posX, posY);
2164 	switch (squareAspect[kDMSquareAspectElement]) {
2165 	case kDMElementTypeStairsSide:
2166 		drawFloorPitOrStairsBitmap(_stairsNativeBitmapIndexSideD0L, frameStairsSideD0L);
2167 		return;
2168 	case kDMElementTypePit:
2169 		drawFloorPitOrStairsBitmap(squareAspect[kDMSquareAspectPitInvisible] ? kDMGraphicIdxFloorPitInvisibleD0L : kDMGraphicIdxFloorPitD0L, frameFloorPitD0L);
2170 		// fall through
2171 	case kDMElementTypeCorridor:
2172 	case kDMElementTypeDoorSide:
2173 	case kDMElementTypeTeleporter:
2174 		drawObjectsCreaturesProjectilesExplosions(Thing(squareAspect[kDMSquareAspectFirstGroupOrObject]), dir, posX, posY, kDMViewSquareD0L, kDMCellOrderBackRight);
2175 		break;
2176 	case kDMElementTypeWall:
2177 		drawWallSetBitmap(_bitmapWallSetWallD0L, _frameWalls163[kDMViewSquareD0L]);
2178 		return;
2179 	default:
2180 		break;
2181 	}
2182 
2183 	drawCeilingPit(kDMGraphicIdxCeilingPitD0L, &frameCeilingPitD0L, posX, posY, false);
2184 	if ((squareAspect[kDMSquareAspectElement] == kDMElementTypeTeleporter) && squareAspect[kDMSquareAspectTeleporterVisible])
2185 		drawField(&_fieldAspects188[kDMViewSquareD0L], _frameWalls163[kDMViewSquareD0L]._box);
2186 }
2187 
drawSquareD0R(Direction dir,int16 posX,int16 posY)2188 void DisplayMan::drawSquareD0R(Direction dir, int16 posX, int16 posY) {
2189 	static Frame frameStairsSideD0R = Frame(208, 223, 73, 85, 8, 13, 0, 0); // @ G0139_s_Graphic558_Frame_StairsSide_D0R
2190 	static Frame frameFloorPitD0R = Frame(192, 223, 124, 135, 16, 12, 0, 0); // @ G0151_s_Graphic558_Frame_FloorPit_D0R
2191 	static Frame frameCeilingPitD0R = Frame(208, 223, 0, 3, 8, 4, 0, 0); // @ G0160_s_Graphic558_Frame_CeilingPit_D0R
2192 
2193 	uint16 squareAspect[5];
2194 
2195 	_vm->_dungeonMan->setSquareAspect(squareAspect, dir, posX, posY);
2196 	switch (squareAspect[kDMSquareAspectElement]) {
2197 	case kDMElementTypeStairsSide:
2198 		drawFloorPitOrStairsBitmapFlippedHorizontally(_stairsNativeBitmapIndexSideD0L, frameStairsSideD0R);
2199 		return;
2200 	case kDMElementTypePit:
2201 		drawFloorPitOrStairsBitmapFlippedHorizontally(squareAspect[kDMSquareAspectPitInvisible] ? kDMGraphicIdxFloorPitInvisibleD0L
2202 														   : kDMGraphicIdxFloorPitD0L, frameFloorPitD0R);
2203 		// fall through
2204 	case kDMElementTypeCorridor:
2205 	case kDMElementTypeDoorSide:
2206 	case kDMElementTypeTeleporter:
2207 		drawCeilingPit(kDMGraphicIdxCeilingPitD0L, &frameCeilingPitD0R, posX, posY, true);
2208 		drawObjectsCreaturesProjectilesExplosions(Thing(squareAspect[kDMSquareAspectFirstGroupOrObject]), dir, posX, posY, kDMViewSquareD0R, kDMCellOrderBackLeft);
2209 		break;
2210 	case kDMElementTypeWall:
2211 		drawWallSetBitmap(_bitmapWallSetWallD0R, _frameWalls163[kDMViewSquareD0R]);
2212 		return;
2213 	default:
2214 		break;
2215 	}
2216 	if ((squareAspect[kDMSquareAspectElement] == kDMElementTypeTeleporter) && squareAspect[kDMSquareAspectTeleporterVisible])
2217 		drawField(&_fieldAspects188[kDMViewSquareD0R], _frameWalls163[kDMViewSquareD0R]._box);
2218 }
2219 
drawSquareD0C(Direction dir,int16 posX,int16 posY)2220 void DisplayMan::drawSquareD0C(Direction dir, int16 posX, int16 posY) {
2221 	static Frame doorFrameD0C = Frame(96, 127, 0, 122, 16, 123, 0, 0); // @ G0172_s_Graphic558_Frame_DoorFrame_D0C
2222 	static Frame frameStairsUpFrontD0L = Frame(0, 31, 58, 101, 16, 44, 0, 0); // @ G0119_s_Graphic558_Frame_StairsUpFront_D0L
2223 	static Frame frameStairsDownFrontD0L = Frame(0, 31, 76, 135, 16, 60, 0, 0); // @ G0130_s_Graphic558_Frame_StairsDownFront_D0L
2224 	static Frame frameStairsUpFrontD0R = Frame(192, 223, 58, 101, 16, 44, 0, 0); // @ G0120_s_Graphic558_Frame_StairsUpFront_D0R
2225 	static Frame frameStairsDownFrontD0R = Frame(192, 223, 76, 135, 16, 60, 0, 0); // @ G0131_s_Graphic558_Frame_StairsDownFront_D0R
2226 	static Frame frameFloorPitD0C = Frame(16, 207, 124, 135, 96, 12, 0, 0); // @ G0150_s_Graphic558_Frame_FloorPit_D0C
2227 	static Frame frameCeilingPitD0C = Frame(16, 207, 0, 3, 96, 4, 0, 0); // @ G0159_s_Graphic558_Frame_CeilingPit_D0C
2228 	static Box boxThievesEyeHoleInDoorFrame(0, 31, 19, 113); // @ G0108_s_Graphic558_Box_ThievesEye_HoleInDoorFrame
2229 
2230 	ChampionMan &championMan = *_vm->_championMan;
2231 
2232 	uint16 squareAspect[5];
2233 
2234 	_vm->_dungeonMan->setSquareAspect(squareAspect, dir, posX, posY);
2235 	switch (squareAspect[kDMSquareAspectElement]) {
2236 	case kDMElementTypeDoorSide:
2237 		if (championMan._party._event73Count_ThievesEye) {
2238 			memmove(_tmpBitmap, _bitmapWallSetDoorFrameFront, 32 * 123);
2239 			blitToBitmap(getNativeBitmapOrGraphic(kDMGraphicIdxHoleInWall),
2240 							  _tmpBitmap, boxThievesEyeHoleInDoorFrame, doorFrameD0C._box._rect.left - _boxThievesEyeViewPortVisibleArea._rect.left,
2241 							  0, 48, 16, kDMColorGold, 95, 123);
2242 			drawWallSetBitmap(_tmpBitmap, doorFrameD0C);
2243 		} else
2244 			drawWallSetBitmap(_bitmapWallSetDoorFrameFront, doorFrameD0C);
2245 		break;
2246 	case kDMElementTypeStairsFront:
2247 		if (squareAspect[kDMSquareAspectStairsUp]) {
2248 			drawFloorPitOrStairsBitmap(_stairsNativeBitmapIndexUpFrontD0CLeft, frameStairsUpFrontD0L);
2249 			drawFloorPitOrStairsBitmapFlippedHorizontally(_stairsNativeBitmapIndexUpFrontD0CLeft, frameStairsUpFrontD0R);
2250 		} else {
2251 			drawFloorPitOrStairsBitmap(_stairsNativeBitmapIndexDownFrontD0CLeft, frameStairsDownFrontD0L);
2252 			drawFloorPitOrStairsBitmapFlippedHorizontally(_stairsNativeBitmapIndexDownFrontD0CLeft, frameStairsDownFrontD0R);
2253 		}
2254 		break;
2255 	case kDMElementTypePit:
2256 		drawFloorPitOrStairsBitmap(squareAspect[kDMSquareAspectPitInvisible] ? kDMGraphicIdxFloorPitInvisibleD0C : kDMGraphicIdxFloorPitD0C, frameFloorPitD0C);
2257 		break;
2258 	default:
2259 		break;
2260 	}
2261 	drawCeilingPit(kDMGraphicIdxCeilingPitD0C, &frameCeilingPitD0C, posX, posY, false);
2262 	drawObjectsCreaturesProjectilesExplosions(Thing(squareAspect[kDMSquareAspectFirstGroupOrObject]), dir, posX, posY, kDMViewSquareD0C, kDMCellOrderBackLeftBackRight);
2263 	if ((squareAspect[kDMSquareAspectElement] == kDMElementTypeTeleporter) && squareAspect[kDMSquareAspectTeleporterVisible])
2264 		drawField(&_fieldAspects188[kDMViewSquareD0C], _frameWalls163[kDMViewSquareD0C]._box);
2265 }
2266 
drawDungeon(Direction dir,int16 posX,int16 posY)2267 void DisplayMan::drawDungeon(Direction dir, int16 posX, int16 posY) {
2268 	static Frame ceilingFrame(0, 223, 0, 28, 112, 29, 0, 0); // @ K0012_s_Frame_Ceiling
2269 	static Frame floorFrame(0, 223, 66, 135, 112, 70, 0, 0); // @ K0013_s_Frame_Floor
2270 	static Frame frameWallD3L2 = Frame(0, 15, 25, 73, 8, 49, 0, 0); // @ G0711_s_Graphic558_Frame_Wall_D3L2
2271 
2272 	DungeonMan &dungeon = *_vm->_dungeonMan;
2273 
2274 	if (_drawFloorAndCeilingRequested)
2275 		drawFloorAndCeiling();
2276 
2277 	_useByteBoxCoordinates = true;
2278 	for (int16 i = 0; i < 6; ++i)
2279 		dungeon._dungeonViewClickableBoxes[i].setToZero();
2280 
2281 	for (uint16 i = 0; i < 6; ++i)
2282 		dungeon._dungeonViewClickableBoxes[i]._rect.left = 255;
2283 
2284 	_useFlippedWallAndFootprintsBitmap = (posX + posY + dir) & 1;
2285 	if (_useFlippedWallAndFootprintsBitmap) {
2286 		drawWallSetBitmap(_bitmapCeiling, ceilingFrame);
2287 		copyBitmapAndFlipHorizontal(_bitmapFloor, _tmpBitmap, k112_byteWidthViewport, 70);
2288 		drawWallSetBitmap(_tmpBitmap, floorFrame);
2289 
2290 		_bitmapWallSetD3LCR = _bitmapWallD3LCRFlipped;
2291 		_bitmapWallSetD2LCR = _bitmapWallD2LCRFlipped;
2292 		_bitmapWallSetD1LCR = _bitmapWallD1LCRFlipped;
2293 		_bitmapWallSetWallD0L = _bitmapWallD0LFlipped;
2294 		_bitmapWallSetWallD0R = _bitmapWallD0RFlipped;
2295 	} else {
2296 		copyBitmapAndFlipHorizontal(_bitmapCeiling, _tmpBitmap, k112_byteWidthViewport, 29);
2297 		drawWallSetBitmap(_tmpBitmap, ceilingFrame);
2298 		drawWallSetBitmap(_bitmapFloor, floorFrame);
2299 	}
2300 
2301 	if (dungeon.getRelSquareType(dir, 3, -2, posX, posY) == kDMElementTypeWall)
2302 		drawWallSetBitmap(_bitmapWallSetD3L2, frameWallD3L2);
2303 
2304 	if (dungeon.getRelSquareType(dir, 3, 2, posX, posY) == kDMElementTypeWall)
2305 		drawWallSetBitmap(_bitmapWallSetD3R2, _frameWallD3R2);
2306 
2307 	int16 tmpPosX = posX;
2308 	int16 tmpPosY = posY;
2309 	dungeon.mapCoordsAfterRelMovement(dir, 4, -1, tmpPosX, tmpPosY);
2310 	drawObjectsCreaturesProjectilesExplosions(dungeon.getSquareFirstObject(tmpPosX, tmpPosY), dir, tmpPosX, tmpPosY, kViewSquareD4L, kDMCellOrderBackLeft);
2311 	tmpPosX = posX;
2312 	tmpPosY = posY;
2313 	dungeon.mapCoordsAfterRelMovement(dir, 4, 1, tmpPosX, tmpPosY);
2314 	drawObjectsCreaturesProjectilesExplosions(dungeon.getSquareFirstObject(tmpPosX, tmpPosY), dir, tmpPosX, tmpPosY, kDMViewSquareD4R, kDMCellOrderBackLeft);
2315 	tmpPosX = posX;
2316 	tmpPosY = posY;
2317 	dungeon.mapCoordsAfterRelMovement(dir, 4, 0, tmpPosX, tmpPosY);
2318 	drawObjectsCreaturesProjectilesExplosions(dungeon.getSquareFirstObject(tmpPosX, tmpPosY), dir, tmpPosX, tmpPosY, kDMViewSquareD4C, kDMCellOrderBackLeft);
2319 	tmpPosX = posX;
2320 	tmpPosY = posY;
2321 	dungeon.mapCoordsAfterRelMovement(dir, 3, -1, tmpPosX, tmpPosY);
2322 	drawSquareD3L(dir, tmpPosX, tmpPosY);
2323 	tmpPosX = posX;
2324 	tmpPosY = posY;
2325 	dungeon.mapCoordsAfterRelMovement(dir, 3, 1, tmpPosX, tmpPosY);
2326 	drawSquareD3R(dir, tmpPosX, tmpPosY);
2327 	tmpPosX = posX;
2328 	tmpPosY = posY;
2329 	dungeon.mapCoordsAfterRelMovement(dir, 3, 0, tmpPosX, tmpPosY);
2330 	drawSquareD3C(dir, tmpPosX, tmpPosY);
2331 	tmpPosX = posX;
2332 	tmpPosY = posY;
2333 	dungeon.mapCoordsAfterRelMovement(dir, 2, -1, tmpPosX, tmpPosY);
2334 	drawSquareD2L(dir, tmpPosX, tmpPosY);
2335 	tmpPosX = posX;
2336 	tmpPosY = posY;
2337 	dungeon.mapCoordsAfterRelMovement(dir, 2, 1, tmpPosX, tmpPosY);
2338 	drawSquareD2R(dir, tmpPosX, tmpPosY);
2339 	tmpPosX = posX;
2340 	tmpPosY = posY;
2341 	dungeon.mapCoordsAfterRelMovement(dir, 2, 0, tmpPosX, tmpPosY);
2342 	drawSquareD2C(dir, tmpPosX, tmpPosY);
2343 	tmpPosX = posX;
2344 	tmpPosY = posY;
2345 	dungeon.mapCoordsAfterRelMovement(dir, 1, -1, tmpPosX, tmpPosY);
2346 	drawSquareD1L(dir, tmpPosX, tmpPosY);
2347 	tmpPosX = posX;
2348 	tmpPosY = posY;
2349 	dungeon.mapCoordsAfterRelMovement(dir, 1, 1, tmpPosX, tmpPosY);
2350 	drawSquareD1R(dir, tmpPosX, tmpPosY);
2351 	tmpPosX = posX;
2352 	tmpPosY = posY;
2353 	dungeon.mapCoordsAfterRelMovement(dir, 1, 0, tmpPosX, tmpPosY);
2354 	drawSquareD1C(dir, tmpPosX, tmpPosY);
2355 	tmpPosX = posX;
2356 	tmpPosY = posY;
2357 	dungeon.mapCoordsAfterRelMovement(dir, 0, -1, tmpPosX, tmpPosY);
2358 	drawSquareD0L(dir, tmpPosX, tmpPosY);
2359 	tmpPosX = posX;
2360 	tmpPosY = posY;
2361 	dungeon.mapCoordsAfterRelMovement(dir, 0, 1, tmpPosX, tmpPosY);
2362 	drawSquareD0R(dir, tmpPosX, tmpPosY);
2363 	drawSquareD0C(dir, posX, posY);
2364 
2365 	if (_useFlippedWallAndFootprintsBitmap) {
2366 		_bitmapWallSetD3LCR = _bitmapWallD3LCRNative;
2367 		_bitmapWallSetD2LCR = _bitmapWallD2LCRNative;
2368 		_bitmapWallSetD1LCR = _bitmapWallD1LCRNative;
2369 		_bitmapWallSetWallD0L = _bitmapWallD0LNative;
2370 		_bitmapWallSetWallD0R = _bitmapWallD0RNative;
2371 	}
2372 
2373 	drawViewport((dungeon._partyMapIndex != kDMMapIndexEntrance) ? 1 : 0);
2374 	if (dungeon._partyMapIndex != kDMMapIndexEntrance)
2375 		drawFloorAndCeiling();
2376 }
2377 
drawFloorAndCeiling()2378 void DisplayMan::drawFloorAndCeiling() {
2379 	Box box(0, 223, 0, 36);
2380 	fillBoxBitmap(_bitmapViewport, box, kDMColorBlack, k112_byteWidthViewport, k136_heightViewport);
2381 	_drawFloorAndCeilingRequested = false;
2382 }
2383 
fillScreen(Color color)2384 void DisplayMan::fillScreen(Color color) {
2385 	memset(getCurrentVgaBuffer(), color, sizeof(byte) * _screenWidth * _screenHeight);
2386 }
2387 
fillBitmap(byte * bitmap,Color color,uint16 byteWidth,uint16 height)2388 void DisplayMan::fillBitmap(byte *bitmap, Color color, uint16 byteWidth, uint16 height) {
2389 	uint16 width = byteWidth * 2;
2390 	memset(bitmap, color, sizeof(byte) * width * height);
2391 }
2392 
loadFloorSet(FloorSet set)2393 void DisplayMan::loadFloorSet(FloorSet set) {
2394 	if (_currentFloorSet == set)
2395 		return;
2396 
2397 	_currentFloorSet = set;
2398 	int16 index = (set * k2_FloorSetGraphicCount) + k75_FirstFloorSet;
2399 	loadIntoBitmap(index, _bitmapFloor);
2400 	loadIntoBitmap(index + 1, _bitmapCeiling);
2401 }
2402 
loadWallSet(WallSet set)2403 void DisplayMan::loadWallSet(WallSet set) {
2404 	if ((_currentWallSet == set) && !_vm->_restartGameRequest)
2405 		return;
2406 
2407 	_currentWallSet = set;
2408 
2409 	int16 graphicIndice = (set * k13_WallSetGraphicCount) + k77_FirstWallSet;
2410 	loadIntoBitmap(graphicIndice++, _bitmapWallSetDoorFrameFront);
2411 	loadIntoBitmap(graphicIndice++, _bitmapWallSetDoorFrameLeftD1C);
2412 	loadIntoBitmap(graphicIndice++, _bitmapWallSetDoorFrameLeftD2C);
2413 	loadIntoBitmap(graphicIndice++, _bitmapWallSetDoorFrameLeftD3C);
2414 	loadIntoBitmap(graphicIndice++, _bitmapWallSetDoorFrameLeftD3L);
2415 	loadIntoBitmap(graphicIndice++, _bitmapWallSetDoorFrameTopD1LCR);
2416 	loadIntoBitmap(graphicIndice++, _bitmapWallSetDoorFrameTopD2LCR);
2417 	loadIntoBitmap(graphicIndice++, _bitmapWallSetWallD0R);
2418 	loadIntoBitmap(graphicIndice++, _bitmapWallSetWallD0L);
2419 	loadIntoBitmap(graphicIndice++, _bitmapWallSetD1LCR);
2420 	loadIntoBitmap(graphicIndice++, _bitmapWallSetD2LCR);
2421 	loadIntoBitmap(graphicIndice++, _bitmapWallSetD3LCR);
2422 	loadIntoBitmap(graphicIndice++, _bitmapWallSetD3L2);
2423 
2424 	copyBitmapAndFlipHorizontal(_bitmapWallSetDoorFrameLeftD1C, _bitmapWallSetDoorFrameRightD1C,
2425 									_doorFrameRightD1C._srcByteWidth, _doorFrameRightD1C._srcHeight);
2426 	copyBitmapAndFlipHorizontal(_bitmapWallSetD3L2, _bitmapWallSetD3R2,
2427 									_frameWallD3R2._srcByteWidth, _frameWallD3R2._srcHeight);
2428 }
2429 
loadCurrentMapGraphics()2430 void DisplayMan::loadCurrentMapGraphics() {
2431 	static Box boxWallD3LCR = Box(0, 115, 0, 50); // @ G0161_s_Graphic558_Box_WallBitmap_D3LCR
2432 	static Box boxWallD2LCR = Box(0, 135, 0, 70); // @ G0162_s_Graphic558_Box_WallBitmap_D2LCR
2433 	static byte doorOrnCoordIndices[12] = { // @ G0196_auc_Graphic558_DoorOrnamentCoordinateSetIndices
2434 		0,   /* Door Ornament #00 Square Grid */
2435 		1,   /* Door Ornament #01 Iron Bars */
2436 		1,   /* Door Ornament #02 Jewels */
2437 		1,   /* Door Ornament #03 Wooden Bars */
2438 		0,   /* Door Ornament #04 Arched Grid */
2439 		2,   /* Door Ornament #05 Block Lock */
2440 		3,   /* Door Ornament #06 Corner Lock */
2441 		1,   /* Door Ornament #07 Black door */
2442 		2,   /* Door Ornament #08 Red Triangle Lock */
2443 		2,   /* Door Ornament #09 Triangle Lock */
2444 		1,   /* Door Ornament #10 Ra Door */
2445 		1    /* Door Ornament #11 Iron Door Damages */
2446 	};
2447 	static byte floorOrnCoordSetIndices[9] = { // @ G0195_auc_Graphic558_FloorOrnamentCoordinateSetIndices
2448 		0,   /* Floor Ornament 00 Square Grate */
2449 		0,   /* Floor Ornament 01 Square Pressure Pad */
2450 		0,   /* Floor Ornament 02 Moss */
2451 		0,   /* Floor Ornament 03 Round Grate */
2452 		2,   /* Floor Ornament 04 Round Pressure Plate */
2453 		0,   /* Floor Ornament 05 Black Flame Pit */
2454 		0,   /* Floor Ornament 06 Crack */
2455 		2,   /* Floor Ornament 07 Tiny Pressure Pad */
2456 		0    /* Floor Ornament 08 Puddle */
2457 	};
2458 	static byte g194_WallOrnCoordSetIndices[60] = { // @ G0194_auc_Graphic558_WallOrnamentCoordinateSetIndices
2459 		1,   /* Wall Ornament 00 Unreadable Inscription */
2460 		1,   /* Wall Ornament 01 Square Alcove */
2461 		1,   /* Wall Ornament 02 Vi Altar */
2462 		1,   /* Wall Ornament 03 Arched Alcove */
2463 		0,   /* Wall Ornament 04 Hook */
2464 		0,   /* Wall Ornament 05 Iron Lock */
2465 		0,   /* Wall Ornament 06 Wood Ring */
2466 		0,   /* Wall Ornament 07 Small Switch */
2467 		0,   /* Wall Ornament 08 Dent 1 */
2468 		0,   /* Wall Ornament 09 Dent 2 */
2469 		0,   /* Wall Ornament 10 Iron Ring */
2470 		2,   /* Wall Ornament 11 Crack */
2471 		3,   /* Wall Ornament 12 Slime Outlet */
2472 		0,   /* Wall Ornament 13 Dent 3 */
2473 		0,   /* Wall Ornament 14 Tiny Switch */
2474 		0,   /* Wall Ornament 15 Green Switch Out */
2475 		0,   /* Wall Ornament 16 Blue Switch Out */
2476 		0,   /* Wall Ornament 17 Coin Slot */
2477 		0,   /* Wall Ornament 18 Double Iron Lock */
2478 		0,   /* Wall Ornament 19 Square Lock */
2479 		0,   /* Wall Ornament 20 Winged Lock */
2480 		0,   /* Wall Ornament 21 Onyx Lock */
2481 		0,   /* Wall Ornament 22 Stone Lock */
2482 		0,   /* Wall Ornament 23 Cross Lock */
2483 		0,   /* Wall Ornament 24 Topaz Lock */
2484 		0,   /* Wall Ornament 25 Skeleton Lock */
2485 		0,   /* Wall Ornament 26 Gold Lock */
2486 		0,   /* Wall Ornament 27 Tourquoise Lock */
2487 		0,   /* Wall Ornament 28 Emerald Lock */
2488 		0,   /* Wall Ornament 29 Ruby Lock */
2489 		0,   /* Wall Ornament 30 Ra Lock */
2490 		0,   /* Wall Ornament 31 Master Lock */
2491 		0,   /* Wall Ornament 32 Gem Hole */
2492 		2,   /* Wall Ornament 33 Slime */
2493 		2,   /* Wall Ornament 34 Grate */
2494 		1,   /* Wall Ornament 35 Fountain */
2495 		1,   /* Wall Ornament 36 Manacles */
2496 		1,   /* Wall Ornament 37 Ghoul's Head */
2497 		1,   /* Wall Ornament 38 Empty Torch Holder */
2498 		1,   /* Wall Ornament 39 Scratches */
2499 		4,   /* Wall Ornament 40 Poison Holes */
2500 		4,   /* Wall Ornament 41 Fireball Holes */
2501 		4,   /* Wall Ornament 42 Dagger Holes */
2502 		5,   /* Wall Ornament 43 Champion Mirror */
2503 		0,   /* Wall Ornament 44 Lever Up */
2504 		0,   /* Wall Ornament 45 Lever Down */
2505 		1,   /* Wall Ornament 46 Full Torch Holder */
2506 		0,   /* Wall Ornament 47 Red Switch Out */
2507 		0,   /* Wall Ornament 48 Eye Switch */
2508 		0,   /* Wall Ornament 49 Big Switch Out */
2509 		2,   /* Wall Ornament 50 Crack Switch Out */
2510 		0,   /* Wall Ornament 51 Green Switch In */
2511 		0,   /* Wall Ornament 52 Blue Switch In */
2512 		0,   /* Wall Ornament 53 Red Switch In */
2513 		0,   /* Wall Ornament 54 Big Switch In */
2514 		2,   /* Wall Ornament 55 Crack Switch In. Atari ST Version 1.0 1987-12-08: 0  */
2515 		6,   /* Wall Ornament 56 Amalgam (Encased Gem) */
2516 		6,   /* Wall Ornament 57 Amalgam (Free Gem) */
2517 		6,   /* Wall Ornament 58 Amalgam (Without Gem) */
2518 		7    /* Wall Ornament 59 Lord Order (Outside) */
2519 	};
2520 	static byte g192_AlcoveOrnIndices[k3_AlcoveOrnCount] = { // @ G0192_auc_Graphic558_AlcoveOrnamentIndices
2521 		1,   /* Square Alcove */
2522 		2,   /* Vi Altar */
2523 		3};  /* Arched Alcove */
2524 	static int16 g193_FountainOrnIndices[k1_FountainOrnCount] = {35}; // @ G0193_ai_Graphic558_FountainOrnamentIndices
2525 
2526 	DungeonMan &dungeon = *_vm->_dungeonMan;
2527 
2528 	loadFloorSet(dungeon._currMap->_floorSet);
2529 	loadWallSet(dungeon._currMap->_wallSet);
2530 
2531 	_useByteBoxCoordinates = true;
2532 
2533 	copyBitmapAndFlipHorizontal(_bitmapWallD3LCRNative = _bitmapWallSetD3LCR, _tmpBitmap,
2534 									_frameWalls163[kDMViewSquareD3C]._srcByteWidth, _frameWalls163[kDMViewSquareD3C]._srcHeight);
2535 	fillBitmap(_bitmapWallD3LCRFlipped, kDMColorFlesh, 64, 51);
2536 	blitToBitmap(_tmpBitmap, _bitmapWallD3LCRFlipped, boxWallD3LCR, 11, 0, 64, 64, kDMColorNoTransparency, 51, 51);
2537 
2538 	copyBitmapAndFlipHorizontal(_bitmapWallD2LCRNative = _bitmapWallSetD2LCR, _tmpBitmap,
2539 									_frameWalls163[kDMViewSquareD2C]._srcByteWidth, _frameWalls163[kDMViewSquareD2C]._srcHeight);
2540 	fillBitmap(_bitmapWallD2LCRFlipped, kDMColorFlesh, 72, 71);
2541 	blitToBitmap(_tmpBitmap, _bitmapWallD2LCRFlipped, boxWallD2LCR, 8, 0, 72, 72, kDMColorNoTransparency, 71, 71);
2542 
2543 	copyBitmapAndFlipHorizontal(_bitmapWallD1LCRNative = _bitmapWallSetD1LCR, _bitmapWallD1LCRFlipped,
2544 									_frameWalls163[kDMViewSquareD1C]._srcByteWidth, _frameWalls163[kDMViewSquareD1C]._srcHeight);
2545 	copyBitmapAndFlipHorizontal(_bitmapWallD0LNative = _bitmapWallSetWallD0L, _bitmapWallD0RFlipped,
2546 									_frameWalls163[kDMViewSquareD0L]._srcByteWidth, _frameWalls163[kDMViewSquareD0L]._srcHeight);
2547 	copyBitmapAndFlipHorizontal(_bitmapWallD0RNative = _bitmapWallSetWallD0R, _bitmapWallD0LFlipped,
2548 									_frameWalls163[kDMViewSquareD0L]._srcByteWidth, _frameWalls163[kDMViewSquareD0L]._srcHeight);
2549 
2550 	int16 val = dungeon._currMap->_wallSet * k18_StairsGraphicCount + k90_FirstStairs;
2551 	_stairsNativeBitmapIndexUpFrontD3L = val++;
2552 	_stairsNativeBitmapIndexUpFrontD3C = val++;
2553 	_stairsNativeBitmapIndexUpFrontD2L = val++;
2554 	_stairsNativeBitmapIndexUpFrontD2C = val++;
2555 	_stairsNativeBitmapIndexUpFrontD1L = val++;
2556 	_stairsNativeBitmapIndexUpFrontD1C = val++;
2557 	_stairsNativeBitmapIndexUpFrontD0CLeft = val++;
2558 	_stairsNativeBitmapIndexDownFrontD3L = val++;
2559 	_stairsNativeBitmapIndexDownFrontD3C = val++;
2560 	_stairsNativeBitmapIndexDownFrontD2L = val++;
2561 	_stairsNativeBitmapIndexDownFrontD2C = val++;
2562 	_stairsNativeBitmapIndexDownFrontD1L = val++;
2563 	_stairsNativeBitmapIndexDownFrontD1C = val++;
2564 	_stairsNativeBitmapIndexDownFrontD0CLeft = val++;
2565 	_stairsNativeBitmapIndexSideD2L = val++;
2566 	_stairsNativeBitmapIndexUpSideD1L = val++;
2567 	_stairsNativeBitmapIndexDownSideD1L = val++;
2568 	_stairsNativeBitmapIndexSideD0L = val++;
2569 
2570 	for (int16 i = 0; i < k3_AlcoveOrnCount; ++i)
2571 		_currMapAlcoveOrnIndices[i] = -1;
2572 
2573 	for (int16 i = 0; i < k1_FountainOrnCount; ++i)
2574 		_currMapFountainOrnIndices[i] = -1;
2575 
2576 	uint16 doorSets[2];
2577 	doorSets[0] = dungeon._currMap->_doorSet0;
2578 	doorSets[1] = dungeon._currMap->_doorSet1;
2579 	for (uint16 doorSet = 0; doorSet <= 1; doorSet++) {
2580 		int16 counter = k108_FirstDoorSet + (doorSets[doorSet] * k3_DoorSetGraphicsCount);
2581 		_doorNativeBitmapIndexFrontD3LCR[doorSet] = counter++;
2582 		_doorNativeBitmapIndexFrontD2LCR[doorSet] = counter++;
2583 		_doorNativeBitmapIndexFrontD1LCR[doorSet] = counter++;
2584 	}
2585 
2586 	uint16 alcoveCount = 0;
2587 	uint16 fountainCount = 0;
2588 	Map &currMap = *dungeon._currMap;
2589 
2590 	_currMapViAltarIndex = -1;
2591 
2592 	for (int16 ornamentIndex = 0; ornamentIndex <= currMap._wallOrnCount; ornamentIndex++) {
2593 		uint16 greenOrn = _currMapWallOrnIndices[ornamentIndex];
2594 		/* Each wall ornament has 2 graphics */
2595 		_currMapWallOrnInfo[ornamentIndex].nativeIndice = k121_FirstWallOrn + greenOrn * 2;
2596 		for (int16 ornamentCounter = 0; ornamentCounter < k3_AlcoveOrnCount; ornamentCounter++) {
2597 			if (greenOrn == g192_AlcoveOrnIndices[ornamentCounter]) {
2598 				_currMapAlcoveOrnIndices[alcoveCount++] = ornamentIndex;
2599 				if (greenOrn == 2) /* Wall ornament #2 is the Vi Altar */
2600 					_currMapViAltarIndex = ornamentIndex;
2601 			}
2602 		}
2603 		for (int16 ornamentCounter = 0; ornamentCounter < k1_FountainOrnCount; ornamentCounter++) {
2604 			if (greenOrn == g193_FountainOrnIndices[ornamentCounter])
2605 				_currMapFountainOrnIndices[fountainCount++] = ornamentIndex;
2606 		}
2607 
2608 		_currMapWallOrnInfo[ornamentIndex].coordinateSet = g194_WallOrnCoordSetIndices[greenOrn];
2609 
2610 		byte *coords = _wallOrnamentCoordSets[_currMapWallOrnInfo[ornamentIndex].coordinateSet][0];
2611 
2612 		for (uint16 counter = kDMDerivedBitmapFirstWallOrnament + (ornamentIndex * 4),
2613 					index = counter + 4;
2614 			counter < index;
2615 			coords += ((index - counter) == 2) ? 18 : 12) {
2616 
2617 			releaseBlock(counter | 0x8000);
2618 			_derivedBitmapByteCount[counter++] = coords[4] * coords[5];
2619 		}
2620 	}
2621 
2622 	for (uint16 i = 0; i < currMap._floorOrnCount; ++i) {
2623 		uint16 ornIndice = _currMapFloorOrnIndices[i];
2624 		uint16 nativeIndice = k247_FirstFloorOrn + ornIndice * 6;
2625 		_currMapFloorOrnInfo[i].nativeIndice = nativeIndice;
2626 		_currMapFloorOrnInfo[i].coordinateSet = floorOrnCoordSetIndices[ornIndice];
2627 	}
2628 
2629 
2630 
2631 	for (uint16 i = 0; i < currMap._doorOrnCount; ++i) {
2632 		uint16 ornIndice = _currMapDoorOrnIndices[i];
2633 		_currMapDoorOrnInfo[i].nativeIndice = k303_FirstDoorOrn + ornIndice;
2634 		_currMapDoorOrnInfo[i].coordinateSet = doorOrnCoordIndices[ornIndice];
2635 
2636 		uint16 *coords = _doorOrnCoordSets[_currMapDoorOrnInfo[i].coordinateSet][0];
2637 
2638 		for (uint16 nativeIndice = kDMDerivedBitmapFirstDoorOrnamentD3 + i * 2,
2639 					index = nativeIndice + 2; nativeIndice < index; coords += 6) {
2640 			releaseBlock(nativeIndice | 0x8000);
2641 			_derivedBitmapByteCount[nativeIndice++] = coords[4] * coords[5];
2642 		}
2643 	}
2644 
2645 	for (uint16 index = kDMDerivedBitmapFirstDoorButton, counter = 0; counter < k1_DoorButtonCount; counter++) {
2646 		uint16 *coords = _doorButtonCoordSets[_doorButtonCoordSet[counter]][1];
2647 		_derivedBitmapByteCount[index++] = coords[4] * coords[5];
2648 		coords += 6;
2649 		_derivedBitmapByteCount[index++] = coords[4] * coords[5];
2650 	}
2651 
2652 	applyCreatureReplColors(9, 8);
2653 	applyCreatureReplColors(10, 12);
2654 
2655 	for (uint16 creatureType = 0; creatureType < currMap._creatureTypeCount; ++creatureType) {
2656 		CreatureAspect &aspect = _creatureAspects219[_currMapAllowedCreatureTypes[creatureType]];
2657 		uint16 replColorOrdinal = aspect.getReplColour9();
2658 		if (replColorOrdinal)
2659 			applyCreatureReplColors(9, _vm->ordinalToIndex(replColorOrdinal));
2660 
2661 		replColorOrdinal = aspect.getReplColour10();
2662 		if (replColorOrdinal)
2663 			applyCreatureReplColors(10, _vm->ordinalToIndex(replColorOrdinal));
2664 	}
2665 
2666 	_drawFloorAndCeilingRequested = true;
2667 	_refreshDungeonViewPaleteRequested = true;
2668 }
2669 
applyCreatureReplColors(int replacedColor,int replacementColor)2670 void DisplayMan::applyCreatureReplColors(int replacedColor, int replacementColor) {
2671 	CreatureReplColorSet creatureReplColorSets[13] = { // @ G0220_as_Graphic558_CreatureReplacementColorSets
2672 		/* { Color, Color, Color, Color, Color, Color, D2 replacement color index (x10), D3 replacement color index (x10) } */
2673 		CreatureReplColorSet(0x0CA0, 0x0A80, 0x0860, 0x0640, 0x0420, 0x0200,  90,  90),    /* Atari ST: { 0x0650, 0x0540, 0x0430, 0x0320, 0x0210, 0x0100,  90,  90 }, RGB colors are different */
2674 		CreatureReplColorSet(0x0060, 0x0040, 0x0020, 0x0000, 0x0000, 0x0000,   0,   0),    /* Atari ST: { 0x0030, 0x0020, 0x0010, 0x0000, 0x0000, 0x0000,   0,   0 }, */
2675 		CreatureReplColorSet(0x0860, 0x0640, 0x0420, 0x0200, 0x0000, 0x0000, 100, 100),    /* Atari ST: { 0x0430, 0x0320, 0x0210, 0x0100, 0x0000, 0x0000, 100, 100 }, */
2676 		CreatureReplColorSet(0x0640, 0x0420, 0x0200, 0x0000, 0x0000, 0x0000,  90,   0),    /* Atari ST: { 0x0320, 0x0210, 0x0100, 0x0000, 0x0000, 0x0000,  90,   0 }, */
2677 		CreatureReplColorSet(0x000A, 0x0008, 0x0006, 0x0004, 0x0002, 0x0000,  90, 100),    /* Atari ST: { 0x0005, 0x0004, 0x0003, 0x0002, 0x0001, 0x0000,  90, 100 }, */
2678 		CreatureReplColorSet(0x0008, 0x0006, 0x0004, 0x0002, 0x0000, 0x0000, 100,   0),    /* Atari ST: { 0x0004, 0x0003, 0x0002, 0x0001, 0x0000, 0x0000, 100,   0 }, */
2679 		CreatureReplColorSet(0x0808, 0x0606, 0x0404, 0x0202, 0x0000, 0x0000,  90,   0),    /* Atari ST: { 0x0404, 0x0303, 0x0202, 0x0101, 0x0000, 0x0000,  90,   0 }, */
2680 		CreatureReplColorSet(0x0A0A, 0x0808, 0x0606, 0x0404, 0x0202, 0x0000, 100,  90),    /* Atari ST: { 0x0505, 0x0404, 0x0303, 0x0202, 0x0101, 0x0000, 100,  90 }, */
2681 		CreatureReplColorSet(0x0FA0, 0x0C80, 0x0A60, 0x0840, 0x0620, 0x0400, 100,  50),    /* Atari ST: { 0x0750, 0x0640, 0x0530, 0x0420, 0x0310, 0x0200, 100,  50 }, */
2682 		CreatureReplColorSet(0x0F80, 0x0C60, 0x0A40, 0x0820, 0x0600, 0x0200,  50,  70),    /* Atari ST: { 0x0740, 0x0630, 0x0520, 0x0410, 0x0300, 0x0100,  50,  30 }, D3 replacement color index is different */
2683 		CreatureReplColorSet(0x0800, 0x0600, 0x0400, 0x0200, 0x0000, 0x0000, 100, 120),    /* Atari ST: { 0x0400, 0x0300, 0x0200, 0x0100, 0x0000, 0x0000, 100, 100 }, D3 replacement color index is different */
2684 		CreatureReplColorSet(0x0600, 0x0400, 0x0200, 0x0000, 0x0000, 0x0000, 120,   0),    /* Atari ST: { 0x0300, 0x0200, 0x0100, 0x0000, 0x0000, 0x0000, 120,   0 }, */
2685 		CreatureReplColorSet(0x0C86, 0x0A64, 0x0842, 0x0620, 0x0400, 0x0200, 100,  50)     /* Atari ST: { 0x0643, 0x0532, 0x0421, 0x0310, 0x0200, 0x0100, 100,  50 } }; */
2686 	};
2687 
2688 	for (int16 i = 0; i < 6; ++i)
2689 		_palDungeonView[i][replacedColor] = creatureReplColorSets[replacementColor]._RGBColor[i];
2690 
2691 	_palChangesCreatureD2[replacedColor] = creatureReplColorSets[replacementColor]._d2ReplacementColor;
2692 	_palChangesCreatureD3[replacedColor] = creatureReplColorSets[replacementColor]._d3ReplacementColor;
2693 }
2694 
drawFloorPitOrStairsBitmap(uint16 nativeIndex,Frame & f)2695 void DisplayMan::drawFloorPitOrStairsBitmap(uint16 nativeIndex, Frame &f) {
2696 	if (f._srcByteWidth)
2697 		blitToBitmap(getNativeBitmapOrGraphic(nativeIndex), _bitmapViewport, f._box, f._srcX, f._srcY,
2698 						f._srcByteWidth, k112_byteWidthViewport, kDMColorFlesh, f._srcHeight, k136_heightViewport);
2699 }
2700 
drawFloorPitOrStairsBitmapFlippedHorizontally(uint16 nativeIndex,Frame & f)2701 void DisplayMan::drawFloorPitOrStairsBitmapFlippedHorizontally(uint16 nativeIndex, Frame &f) {
2702 	if (f._srcByteWidth) {
2703 		copyBitmapAndFlipHorizontal(getNativeBitmapOrGraphic(nativeIndex), _tmpBitmap, f._srcByteWidth, f._srcHeight);
2704 		blitToBitmap(_tmpBitmap, _bitmapViewport, f._box, f._srcX, f._srcY, f._srcByteWidth,
2705 						k112_byteWidthViewport, kDMColorFlesh, f._srcHeight, k136_heightViewport);
2706 	}
2707 }
2708 
isDrawnWallOrnAnAlcove(int16 wallOrnOrd,ViewWall viewWallIndex)2709 bool DisplayMan::isDrawnWallOrnAnAlcove(int16 wallOrnOrd, ViewWall viewWallIndex) {
2710 	static Box boxWallPatchBehindInscription = Box(110, 113, 37, 63); // @ G0202_ac_Graphic558_Box_WallPatchBehindInscription
2711 	static const byte inscriptionLineY[4] = { // @ G0203_auc_Graphic558_InscriptionLineY
2712 		48,   /* 1 Line  */
2713 		59,   /* 2 lines */
2714 		75,   /* 3 lines */
2715 		86    /* 4 lines */
2716 	};
2717 	static const byte wallOrnDerivedBitmapIndexIncrement[12] = { // @ G0190_auc_Graphic558_WallOrnamentDerivedBitmapIndexIncrement
2718 		0,   /* D3L Right */
2719 		0,   /* D3R Left */
2720 		1,   /* D3L Front */
2721 		1,   /* D3C Front */
2722 		1,   /* D3R Front */
2723 		2,   /* D2L Right */
2724 		2,   /* D2R Left */
2725 		3,   /* D2L Front */
2726 		3,   /* D2C Front */
2727 		3,   /* D2R Front */
2728 		4,   /* D1L Right */
2729 		4    /* D1R Left */
2730 	};
2731 
2732 	static byte unreadableInscriptionBoxY2[15] = { // @ G0204_auc_Graphic558_UnreadableInscriptionBoxY2
2733 		/* { Y for 1 line, Y for 2 lines, Y for 3 lines } */
2734 		45, 48, 53,   /* D3L Right, D3R Left */
2735 		43, 49, 56,   /* D3L Front, D3C Front, D3R Front */
2736 		42, 49, 56,   /* D2L Right, D2R Left */
2737 		46, 53, 63,   /* D2L Front, D2C Front, D2R Front */
2738 		46, 57, 68    /* D1L Right, D1R Left */
2739 	};
2740 
2741 
2742 	static Box boxChampionPortraitOnWall = Box(96, 127, 35, 63); // G0109_s_Graphic558_Box_ChampionPortraitOnWall
2743 
2744 	if (!wallOrnOrd)
2745 		return false;
2746 
2747 	wallOrnOrd--;
2748 	int16 wallOrnamentIndex = wallOrnOrd;
2749 	int16 ornNativeBitmapIndex = _currMapWallOrnInfo[wallOrnamentIndex].nativeIndice;
2750 	int16 wallOrnamentCoordinateSetIndex = _currMapWallOrnInfo[wallOrnamentIndex].coordinateSet;
2751 	byte *ornCoordSet = _wallOrnamentCoordSets[wallOrnamentCoordinateSetIndex][viewWallIndex];
2752 
2753 	DungeonMan &dungeon = *_vm->_dungeonMan;
2754 
2755 	bool isAlcove = dungeon.isWallOrnAnAlcove(wallOrnamentIndex);
2756 	unsigned char inscriptionString[70];
2757 	bool isInscription = (wallOrnamentIndex == dungeon._currMapInscriptionWallOrnIndex);
2758 	if (isInscription)
2759 		dungeon.decodeText((char *)inscriptionString, _inscriptionThing, kDMTextTypeInscription);
2760 
2761 	int16 blitPosX;
2762 	byte *ornBlitBitmap;
2763 
2764 	if (viewWallIndex >= kDMViewWallD1LRight) {
2765 		if (viewWallIndex == kDMViewWallD1CFront) {
2766 			if (isInscription) {
2767 				blitToBitmap(_bitmapWallSetD1LCR, _bitmapViewport, boxWallPatchBehindInscription, 94, 28, _frameWalls163[kDMViewSquareD1C]._srcByteWidth, k112_byteWidthViewport, kDMColorNoTransparency, _frameWalls163[kDMViewSquareD1C]._srcHeight, k136_heightViewport);
2768 				byte *inscrString = inscriptionString;
2769 				byte *L0092_puc_Bitmap = getNativeBitmapOrGraphic(k120_InscriptionFont);
2770 				int16 textLineIndex = 0;
2771 				do {
2772 					int16 characterCount = 0;
2773 					byte *AL0091_puc_Character = inscrString;
2774 					while (*AL0091_puc_Character++ < 128) { /* Hexadecimal: 0x80 (Megamax C does not support hexadecimal character constants) */
2775 						characterCount++;
2776 					}
2777 					Frame blitFrame;
2778 					blitFrame._box._rect.left = 112 - (characterCount << 2);
2779 					blitFrame._box._rect.right = blitFrame._box._rect.left + 7;
2780 					blitFrame._box._rect.bottom = inscriptionLineY[textLineIndex++];
2781 					blitFrame._box._rect.top = blitFrame._box._rect.bottom - 7;
2782 					while (characterCount--) {
2783 						blitToBitmap(L0092_puc_Bitmap, _bitmapViewport, blitFrame._box, *inscrString++ << 3, 0, k144_byteWidth, k112_byteWidthViewport, kDMColorFlesh, 8, k136_heightViewport);
2784 						blitFrame._box._rect.left += 8;
2785 						blitFrame._box._rect.right += 8;
2786 					}
2787 				} while (*inscrString++ != 129); /* Hexadecimal: 0x81 (Megamax C does not support hexadecimal character constants) */
2788 				return isAlcove;
2789 			}
2790 			ornNativeBitmapIndex++;
2791 			Box tmpBox(ornCoordSet[0], ornCoordSet[1], ornCoordSet[2], ornCoordSet[3]);
2792 			dungeon._dungeonViewClickableBoxes[kDMViewCellDoorButtonOrWallOrn] = tmpBox;
2793 			dungeon._isFacingAlcove = isAlcove;
2794 			dungeon._isFacingViAltar = (wallOrnamentIndex == _currMapViAltarIndex);
2795 			dungeon._isFacingFountain = false;
2796 			for (int16 idx = 0; idx < k1_FountainOrnCount; idx++) {
2797 				if (_currMapFountainOrnIndices[idx] == wallOrnamentIndex) {
2798 					dungeon._isFacingFountain = true;
2799 					break;
2800 				}
2801 			}
2802 		}
2803 		ornBlitBitmap = getNativeBitmapOrGraphic(ornNativeBitmapIndex);
2804 		if (viewWallIndex == kDMViewWallD1RLeft) {
2805 			copyBitmapAndFlipHorizontal(ornBlitBitmap, _tmpBitmap, ornCoordSet[4], ornCoordSet[5]);
2806 			ornBlitBitmap = _tmpBitmap;
2807 		}
2808 		blitPosX = 0;
2809 	} else {
2810 		int16 coordinateSetOffset = 0;
2811 		bool flipHorizontal = (viewWallIndex == kDMViewWallD2RLeft) || (viewWallIndex == kDMViewWallD3RLeft);
2812 		if (flipHorizontal)
2813 			ornBlitBitmap = _wallOrnamentCoordSets[wallOrnamentCoordinateSetIndex][kDMViewWallD1RLeft];
2814 		else if ((viewWallIndex == kDMViewWallD2LRight) || (viewWallIndex == kDMViewWallD3LRight))
2815 			ornBlitBitmap = _wallOrnamentCoordSets[wallOrnamentCoordinateSetIndex][kDMViewWallD1LRight];
2816 		else {
2817 			ornNativeBitmapIndex++;
2818 			ornBlitBitmap = _wallOrnamentCoordSets[wallOrnamentCoordinateSetIndex][kDMViewWallD1CFront];
2819 			if (viewWallIndex == kDMViewWallD2LFront)
2820 				coordinateSetOffset = 6;
2821 			else if (viewWallIndex == kDMViewWallD2RFront)
2822 				coordinateSetOffset = -6;
2823 		}
2824 		blitPosX = (ornCoordSet + coordinateSetOffset)[1] - (ornCoordSet + coordinateSetOffset)[0];
2825 		wallOrnamentIndex = kDMDerivedBitmapFirstWallOrnament + (wallOrnamentIndex << 2) + wallOrnDerivedBitmapIndexIncrement[viewWallIndex];
2826 		if (!isDerivedBitmapInCache(wallOrnamentIndex)) {
2827 			byte *blitBitmap = getNativeBitmapOrGraphic(ornNativeBitmapIndex);
2828 			blitToBitmapShrinkWithPalChange(blitBitmap, getDerivedBitmap(wallOrnamentIndex), ornBlitBitmap[4] << 1, ornBlitBitmap[5], ornCoordSet[4] << 1, ornCoordSet[5], (viewWallIndex <= kDMViewWallD3RFront) ? _palChangesDoorButtonAndWallOrnD3 : _palChangesDoorButtonAndWallOrnD2);
2829 			addDerivedBitmap(wallOrnamentIndex);
2830 		}
2831 		ornBlitBitmap = getDerivedBitmap(wallOrnamentIndex);
2832 		if (flipHorizontal) {
2833 			copyBitmapAndFlipHorizontal(ornBlitBitmap, _tmpBitmap, ornCoordSet[4], ornCoordSet[5]);
2834 			ornBlitBitmap = _tmpBitmap;
2835 			blitPosX = 15 - (blitPosX & 0x000F);
2836 		} else if (viewWallIndex == kDMViewWallD2LFront)
2837 			blitPosX -= ornCoordSet[1] - ornCoordSet[0];
2838 		else
2839 			blitPosX = 0;
2840 	}
2841 	byte byteFrame[6];
2842 	if (isInscription) {
2843 		byte *blitBitmap = ornCoordSet;
2844 		byte *inscrString2 = inscriptionString;
2845 		int16 unreadableTextLineCount = 0;
2846 		do {
2847 			while (*inscrString2 < 128) { /* Hexadecimal: 0x80 (Megamax C does not support hexadecimal character constants) */
2848 				inscrString2++;
2849 			}
2850 			unreadableTextLineCount++;
2851 		} while (*inscrString2++ != 129); /* Hexadecimal: 0x81 (Megamax C does not support hexadecimal character constants) */
2852 		ornCoordSet = blitBitmap;
2853 		if (unreadableTextLineCount < 4) {
2854 			for (uint16 i = 0; i < 6; ++i)
2855 				byteFrame[i] = ornCoordSet[i];
2856 			ornCoordSet = byteFrame;
2857 			ornCoordSet[3] = unreadableInscriptionBoxY2[wallOrnDerivedBitmapIndexIncrement[viewWallIndex] * 3 + unreadableTextLineCount - 1];
2858 		}
2859 	}
2860 
2861 	Box tmpBox(ornCoordSet[0], ornCoordSet[1], ornCoordSet[2], ornCoordSet[3]);
2862 	blitToBitmap(ornBlitBitmap, _bitmapViewport, tmpBox, blitPosX, 0,
2863 		ornCoordSet[4], k112_byteWidthViewport, kDMColorFlesh, ornCoordSet[5], k136_heightViewport);
2864 
2865 	if ((viewWallIndex == kDMViewWallD1CFront) && _championPortraitOrdinal--) {
2866 		blitToBitmap(getNativeBitmapOrGraphic(kDMGraphicIdxChampionPortraits), _bitmapViewport, boxChampionPortraitOnWall,
2867 			(_championPortraitOrdinal & 0x0007) << 5, (_championPortraitOrdinal >> 3) * 29,
2868 			k128_byteWidth, k112_byteWidthViewport, kDMColorDarkGary, 87, k136_heightViewport); /* A portrait is 32x29 pixels */
2869 	}
2870 
2871 	return isAlcove;
2872 }
2873 
blitToBitmapShrinkWithPalChange(byte * srcBitmap,byte * destBitmap,int16 srcPixelWidth,int16 srcHeight,int16 destPixelWidth,int16 destHeight,byte * palChange)2874 void DisplayMan::blitToBitmapShrinkWithPalChange(byte *srcBitmap, byte *destBitmap,
2875 													  int16 srcPixelWidth, int16 srcHeight,
2876 													  int16 destPixelWidth, int16 destHeight, byte *palChange) {
2877 	warning("DUMMY CODE: f129_blitToBitmapShrinkWithPalChange");
2878 	warning("MISSING CODE: No palette change takes place in f129_blitToBitmapShrinkWithPalChange");
2879 
2880 
2881 	destPixelWidth = (destPixelWidth + 1) & 0xFFFE;
2882 
2883 	uint32 scaleX = (kScaleThreshold * srcPixelWidth) / destPixelWidth;
2884 	uint32 scaleY = (kScaleThreshold * srcHeight) / destHeight;
2885 
2886 	// Loop through drawing output lines
2887 	for (uint32 destY = 0, scaleYCtr = 0; destY < (uint32)destHeight; ++destY, scaleYCtr += scaleY) {
2888 		const byte *srcLine = &srcBitmap[(scaleYCtr / kScaleThreshold) * srcPixelWidth];
2889 		byte *destLine = &destBitmap[destY * destPixelWidth];
2890 
2891 		// Loop through drawing the pixels of the row
2892 		for (uint32 destX = 0, xCtr = 0, scaleXCtr = 0; destX < (uint32)destPixelWidth; ++destX, ++xCtr, scaleXCtr += scaleX)
2893 			destLine[xCtr] = srcLine[scaleXCtr / kScaleThreshold];
2894 	}
2895 }
2896 
getNativeBitmapOrGraphic(uint16 index)2897 byte *DisplayMan::getNativeBitmapOrGraphic(uint16 index) {
2898 	return _bitmaps[index];
2899 }
2900 
getCompressedData(uint16 index)2901 Common::MemoryReadStream DisplayMan::getCompressedData(uint16 index) {
2902 	return Common::MemoryReadStream(_packedBitmaps + _packedItemPos[index], getCompressedDataSize(index), DisposeAfterUse::NO);
2903 }
2904 
getCompressedDataSize(uint16 index)2905 uint32 DisplayMan::getCompressedDataSize(uint16 index) {
2906 	return _packedItemPos[index + 1] - _packedItemPos[index];
2907 }
2908 
drawField(FieldAspect * fieldAspect,Box & box)2909 void DisplayMan::drawField(FieldAspect *fieldAspect, Box& box) {
2910 	byte *bitmapMask = nullptr;
2911 
2912 	if (fieldAspect->_mask != kMaskFieldAspectNoMask) {
2913 		bitmapMask = _tmpBitmap;
2914 		memmove(bitmapMask, getNativeBitmapOrGraphic(kDMGraphicIdxFieldMaskD3R + getFlag(fieldAspect->_mask, kMaskFieldAspectIndex)),
2915 				fieldAspect->_height * fieldAspect->_byteWidth * 2);
2916 		if (getFlag(fieldAspect->_mask, kMaskFieldAspectFlipMask)) {
2917 			flipBitmapHorizontal(bitmapMask, fieldAspect->_byteWidth, fieldAspect->_height);
2918 		}
2919 	}
2920 
2921 	isDerivedBitmapInCache(kDMDerivedBitmapViewport);
2922 	byte *bitmap = getNativeBitmapOrGraphic(kDMGraphicIdxFieldTeleporter + fieldAspect->_nativeBitmapRelativeIndex);
2923 	blitBoxFilledWithMaskedBitmap(bitmap, _bitmapViewport, bitmapMask, getDerivedBitmap(kDMDerivedBitmapViewport), box,
2924 									   _vm->getRandomNumber(2) + fieldAspect->_baseStartUnitIndex, _vm->getRandomNumber(32), k112_byteWidthViewport,
2925 									   (Color)fieldAspect->_transparentColor, fieldAspect->_xPos, 0, 136, fieldAspect->_bitplaneWordCount);
2926 	addDerivedBitmap(kDMDerivedBitmapViewport);
2927 	releaseBlock(kDMDerivedBitmapViewport | 0x8000);
2928 }
2929 
getScaledBitmapByteCount(int16 byteWidth,int16 height,int16 scale)2930 int16 DisplayMan::getScaledBitmapByteCount(int16 byteWidth, int16 height, int16 scale) {
2931 	return getNormalizedByteWidth(getScaledDimension(byteWidth, scale)) * getScaledDimension(height, scale);
2932 }
2933 
getScaledDimension(int16 dimension,int16 scale)2934 int16 DisplayMan::getScaledDimension(int16 dimension, int16 scale) {
2935 	return (dimension * scale + scale / 2) / 32;
2936 }
2937 
drawObjectsCreaturesProjectilesExplosions(Thing thingParam,Direction directionParam,int16 mapXpos,int16 mapYpos,int16 viewSquareIndex,CellOrder cellOrder)2938 void DisplayMan::drawObjectsCreaturesProjectilesExplosions(Thing thingParam, Direction directionParam, int16 mapXpos,
2939 							  int16 mapYpos, int16 viewSquareIndex, CellOrder cellOrder) {
2940 	int16 AL_0_creatureIndexRed;
2941 #define AL_1_viewSquareExplosionIndex viewSquareIndex
2942 	int16 L0126_i_Multiple;
2943 #define AL_2_viewCell      L0126_i_Multiple
2944 #define AL_2_cellPurpleMan          L0126_i_Multiple
2945 #define AL_2_explosionSize L0126_i_Multiple
2946 	int16 L0127_i_Multiple;
2947 #define AL_4_thingType            L0127_i_Multiple
2948 #define AL_4_nativeBitmapIndex    L0127_i_Multiple
2949 #define AL_4_xPos                    L0127_i_Multiple
2950 #define AL_4_groupCells           L0127_i_Multiple
2951 #define AL_4_normalizdByteWidth  L0127_i_Multiple
2952 #define AL_4_yPos                    L0127_i_Multiple
2953 #define AL_4_projectileAspect     L0127_i_Multiple
2954 #define AL_4_explosionType        L0127_i_Multiple
2955 #define AL_4_explosionAspectIndex L0127_i_Multiple
2956 	ObjectAspect *objectAspect;
2957 	uint32 remainingViewCellOrdinalsToProcess;
2958 	byte *coordinateSet;
2959 	int16 derivedBitmapIndex = -1;
2960 	bool L0135_B_DrawAlcoveObjects;
2961 	int16 byteWidth;
2962 	int16 heightRedEagle;
2963 	ViewLane viewLane; /* The lane (center/left/right) that the specified square is part of */
2964 	int16 cellYellowBear;
2965 	int16 paddingPixelCount;
2966 	int16 heightGreenGoat;
2967 	bool useAlcoveObjectImage; /* true for objects that have a special graphic when drawn in an alcove, like the Chest */
2968 	bool flipHorizontal;
2969 	bool drawingGrabbableObject;
2970 	Box boxByteGreen;
2971 	Thing firstThingToDraw; /* Initialized to thingParam and never changed afterwards. Used as a backup of the specified first object to draw */
2972 	uint16 L0147_ui_Multiple;
2973 #define AL_10_viewSquareIndexBackup L0147_ui_Multiple
2974 #define AL_10_explosionScaleIndex   L0147_ui_Multiple
2975 	int16 cellCounter;
2976 	uint16 objectShiftIndex;
2977 	uint16 L0150_ui_Multiple = 0;
2978 #define AL_8_shiftSetIndex        L0150_ui_Multiple
2979 #define AL_8_projectileScaleIndex L0150_ui_Multiple
2980 	CreatureAspect *creatureAspectStruct = nullptr;
2981 	int16 creatureSize = 0;
2982 	int16 creatureDirectionDelta;
2983 	int16 creatureGraphicInfoGreen = 0;
2984 	int16 creatureGraphicInfoRed;
2985 	int16 creatureAspectInt;
2986 	int16 creatureIndexGreen;
2987 	int16 transparentColor;
2988 	int16 creaturePaddingPixelCount;
2989 	bool drawingLastBackRowCell;
2990 	bool useCreatureSideBitmap;
2991 	bool useCreatureBackBitmap;
2992 	bool useCreatureSpecialD2FrontBitmap;
2993 	bool useCreatureAttackBitmap;
2994 	bool useFlippedHorizontallyCreatureFrontImage;
2995 	bool drawCreaturesCompleted; /* Set to true when the last creature that the function should draw is being drawn. This is used to avoid processing the code to draw creatures for the remaining square cells */
2996 	int16 doorFrontViewDrawingPass; /* Value 0, 1 or 2 */
2997 	int16 projectilePosX = 0;
2998 	int16 projectileDirection;
2999 	int16 projectileAspectType;
3000 	int16 projectileBitmapIndexDelta;
3001 	bool drawProjectileAsObject; /* When true, the code section to draw an object is called (with a goto) to draw the projectile, then the code section goes back to projectile processing with another goto */
3002 	uint16 currentViewCellToDraw = 0;
3003 	bool projectileFlipVertical = false;
3004 
3005 	/* This is the full dungeon view */
3006 	static Box boxExplosionPatternD0C = Box(0, 223, 0, 135); // @ G0105_s_Graphic558_Box_ExplosionPattern_D0C
3007 
3008 	static byte explosionBaseScales[5] = { // @ G0216_auc_Graphic558_ExplosionBaseScales
3009 		10,  /* D4 */
3010 		16,  /* D3 */
3011 		23,  /* D2 */
3012 		32,  /* D1 */
3013 		32   /* D0 */
3014 	};
3015 
3016 	static byte objectPileShiftSetIndices[16][2] = { // @ G0217_aauc_Graphic558_ObjectPileShiftSetIndices
3017 	/* { X shift index, Y shift index } */
3018 		{2, 5},
3019 		{0, 6},
3020 		{5, 7},
3021 		{3, 0},
3022 		{7, 1},
3023 		{1, 2},
3024 		{6, 3},
3025 		{3, 3},
3026 		{5, 5},
3027 		{2, 6},
3028 		{7, 7},
3029 		{1, 0},
3030 		{3, 1},
3031 		{6, 2},
3032 		{1, 3},
3033 		{5, 3}
3034 	};
3035 
3036 	static byte objectCoordinateSets[3][10][5][2] = { // @ G0218_aaaauc_Graphic558_ObjectCoordinateSets
3037 	/* { {X, Y }, {X, Y }, {X, Y }, {X, Y }, {X, Y } } */
3038 		{
3039 			{{  0,   0}, {  0,   0}, {125,  72}, { 95,  72}, {112, 64}},     /* D3C */
3040 			{{  0,   0}, {  0,   0}, { 62,  72}, { 25,  72}, { 24, 64}},     /* D3L */
3041 			{{  0,   0}, {  0,   0}, {200,  72}, {162,  72}, {194, 64}},     /* D3R */
3042 			{{ 92,  78}, {132,  78}, {136,  86}, { 88,  86}, {112, 74}},     /* D2C */
3043 			{{ 10,  78}, { 53,  78}, { 41,  86}, {  0,   0}, {  3, 74}},     /* D2L */
3044 			{{171,  78}, {218,  78}, {  0,   0}, {183,  86}, {219, 74}},     /* D2R */
3045 			{{ 83,  96}, {141,  96}, {148, 111}, { 76, 111}, {112, 94}},     /* D1C */
3046 			{{  0,   0}, { 26,  96}, {  5, 111}, {  0,   0}, {  0,  0}},     /* D1L */
3047 			{{197,  96}, {  0,   0}, {  0,   0}, {220, 111}, {  0,  0}},     /* D1R */
3048 			{{ 66, 131}, {158, 131}, {  0,   0}, {  0,   0}, {  0,  0}}      /* D0C */
3049 		},
3050 		{
3051 			{{  0,   0}, {  0,   0}, {125,  72}, { 95,  72}, {112, 63}},     /* D3C */
3052 			{{  0,   0}, {  0,   0}, { 62,  72}, { 25,  72}, { 24, 63}},     /* D3L */
3053 			{{  0,   0}, {  0,   0}, {200,  72}, {162,  72}, {194, 63}},     /* D3R */
3054 			{{ 92,  78}, {132,  78}, {136,  86}, { 88,  86}, {112, 73}},     /* D2C */
3055 			{{ 10,  78}, { 53,  78}, { 41,  86}, {  0,   0}, {  3, 73}},     /* D2L */
3056 			{{171,  78}, {218,  78}, {  0,   0}, {183,  86}, {219, 73}},     /* D2R */
3057 			{{ 83,  96}, {141,  96}, {148, 111}, { 76, 111}, {112, 89}},     /* D1C */
3058 			{{  0,   0}, { 26,  96}, {  5, 111}, {  0,   0}, {  0,  0}},     /* D1L */
3059 			{{197,  96}, {  0,   0}, {  0,   0}, {220, 111}, {  0,  0}},     /* D1R */
3060 			{{ 66, 131}, {158, 131}, {  0,   0}, {  0,   0}, {  0,  0}}      /* D0C */
3061 		},
3062 		{
3063 			{{  0,   0}, {  0,   0}, {125,  75}, { 95,  75}, {112, 65}},     /* D3C */
3064 			{{  0,   0}, {  0,   0}, { 62,  75}, { 25,  75}, { 24, 65}},     /* D3L */
3065 			{{  0,   0}, {  0,   0}, {200,  75}, {162,  75}, {194, 65}},     /* D3R */
3066 			{{ 92,  81}, {132,  81}, {136,  88}, { 88,  88}, {112, 76}},     /* D2C */
3067 			{{ 10,  81}, { 53,  81}, { 41,  88}, {  0,   0}, {  3, 76}},     /* D2L */
3068 			{{171,  81}, {218,  81}, {  0,   0}, {183,  88}, {219, 76}},     /* D2R */
3069 			{{ 83,  98}, {141,  98}, {148, 115}, { 76, 115}, {112, 98}},     /* D1C */
3070 			{{  0,   0}, { 26,  98}, {  5, 115}, {  0,   0}, {  0,  0}},     /* D1L */
3071 			{{197,  98}, {  0,   0}, {  0,   0}, {220, 115}, {  0,  0}},     /* D1R */
3072 			{{ 66, 135}, {158, 135}, {  0,   0}, {  0,   0}, {  0,  0}}      /* D0C */
3073 		}
3074 	};
3075 
3076 	static int16 shiftSets[3][8] = { // @ G0223_aac_Graphic558_ShiftSets
3077 		{0, 1, 2, 3, 0, -3, -2, -1},   /* D0 Back or D1 Front */
3078 		{0, 1, 1, 2, 0, -2, -1, -1},   /* D1 Back or D2 Front */
3079 		{0, 1, 1, 1, 0, -1, -1, -1}    /* D2 Back or D3 Front */
3080 	};
3081 
3082 	static byte creatureCoordinateSets[3][11][5][2] = { // @ G0224_aaaauc_Graphic558_CreatureCoordinateSets
3083 	/* { { X, Y }, { X, Y }, { X, Y }, { X, Y }, { X, Y } } */
3084 		{
3085 			{{ 95,  70}, {127,  70}, {129,  75}, { 93,  75}, {111,  72}},     /* D3C */
3086 			{{131,  70}, {163,  70}, {158,  75}, {120,  75}, {145,  72}},     /* D3L */
3087 			{{ 59,  70}, { 91,  70}, {107,  75}, { 66,  75}, { 79,  72}},     /* D3R */
3088 			{{ 92,  81}, {131,  81}, {132,  90}, { 91,  90}, {111,  85}},     /* D2C */
3089 			{{ 99,  81}, {146,  81}, {135,  90}, { 80,  90}, {120,  85}},     /* D2L */
3090 			{{ 77,  81}, {124,  81}, {143,  90}, { 89,  90}, {105,  85}},     /* D2R */
3091 			{{ 83, 103}, {141, 103}, {148, 119}, { 76, 119}, {109, 111}},     /* D1C */
3092 			{{ 46, 103}, {118, 103}, {101, 119}, {  0,   0}, { 79, 111}},     /* D1L */
3093 			{{107, 103}, {177, 103}, {  0,   0}, {123, 119}, {144, 111}},     /* D1R */
3094 			{{  0,   0}, { 67, 135}, {  0,   0}, {  0,   0}, {  0,   0}},     /* D0L */
3095 			{{156, 135}, {  0,   0}, {  0,   0}, {  0,   0}, {  0,   0}}      /* D0R */
3096 		},
3097 		{
3098 			{{ 94,  75}, {128,  75}, {111,  70}, {111,  72}, {111,  75}},     /* D3C */
3099 			{{120,  75}, {158,  75}, {149,  70}, {145,  72}, {150,  75}},     /* D3L */
3100 			{{ 66,  75}, {104,  75}, { 75,  70}, { 79,  72}, { 73,  75}},     /* D3R */
3101 			{{ 91,  90}, {132,  90}, {111,  83}, {111,  85}, {111,  90}},     /* D2C */
3102 			{{ 80,  90}, {135,  90}, {125,  83}, {120,  85}, {125,  90}},     /* D2L */
3103 			{{ 89,  90}, {143,  90}, { 99,  83}, {105,  85}, { 98,  90}},     /* D2R */
3104 			{{ 81, 119}, {142, 119}, {111, 105}, {111, 111}, {111, 119}},     /* D1C */
3105 			{{  0,   0}, {101, 119}, { 84, 105}, { 70, 111}, { 77, 119}},     /* D1L */
3106 			{{123, 119}, {  0,   0}, {139, 105}, {153, 111}, {146, 119}},     /* D1R */
3107 			{{  0,   0}, { 83, 130}, { 57, 121}, { 47, 126}, { 57, 130}},     /* D0L */
3108 			{{140, 130}, {  0,   0}, {166, 121}, {176, 126}, {166, 130}}      /* D0R */
3109 		},
3110 		{
3111 			{{ 95,  59}, {127,  59}, {129,  61}, { 93,  61}, {111,  60}},     /* D3C */
3112 			{{131,  59}, {163,  59}, {158,  61}, {120,  61}, {145,  60}},     /* D3L */
3113 			{{ 59,  59}, { 91,  59}, {107,  61}, { 66,  61}, { 79,  60}},     /* D3R */
3114 			{{ 92,  65}, {131,  65}, {132,  67}, { 91,  67}, {111,  66}},     /* D2C */
3115 			{{ 99,  65}, {146,  65}, {135,  67}, { 80,  67}, {120,  66}},     /* D2L */
3116 			{{ 77,  65}, {124,  65}, {143,  67}, { 89,  67}, {105,  66}},     /* D2R */
3117 			{{ 83,  79}, {141,  79}, {148,  85}, { 76,  85}, {111,  81}},     /* D1C */
3118 			{{ 46,  79}, {118,  79}, {101,  85}, {  0,   0}, { 79,  81}},     /* D1L */
3119 			{{107,  79}, {177,  79}, {  0,   0}, {123,  85}, {144,  81}},     /* D1R */
3120 			{{  0,   0}, { 67,  96}, {  0,   0}, {  0,   0}, {  0,   0}},     /* D0L */
3121 			{{156,  96}, {  0,   0}, {  0,   0}, {  0,   0}, {  0,   0}}      /* D0R */
3122 		}
3123 	};
3124 
3125 	static int16 explosionCoordinatesArray[15][2][2] = { // @ G0226_aaai_Graphic558_ExplosionCoordinates
3126 	/* { { Front Left X, Front Left Y }, { Front Right X, Front Right Y } } */
3127 		{{100, 47}, {122, 47}},   /* D4C */
3128 		{{ 52, 47}, { 76, 47}},   /* D4L */
3129 		{{148, 47}, {172, 47}},   /* D4R */
3130 		{{ 95, 50}, {127, 50}},   /* D3C */
3131 		{{ 31, 50}, { 63, 50}},   /* D3L */
3132 		{{159, 50}, {191, 50}},   /* D3R */
3133 		{{ 92, 53}, {131, 53}},   /* D2C */
3134 		{{ -3, 53}, { 46, 53}},   /* D2L */
3135 		{{177, 53}, {226, 53}},   /* D2R */
3136 		{{ 83, 57}, {141, 57}},   /* D1C */
3137 		{{-54, 57}, { 18, 57}},   /* D1L */
3138 		{{207, 57}, {277, 57}},   /* D1R */
3139 		{{  0,  0}, {  0,  0}},   /* D0C */
3140 		{{-73, 60}, {-33, 60}},   /* D0L */
3141 		{{256, 60}, {296, 60}}    /* D0R */
3142 	};
3143 
3144 	static int16 rebirthStep2ExplosionCoordinates[7][3] = { // @ G0227_aai_Graphic558_RebirthStep2ExplosionCoordinates
3145 	/* { X, Y, Scale } */
3146 		{113, 57, 12},   /* D3C */
3147 		{ 24, 57, 12},   /* D3L */
3148 		{195, 57, 12},   /* D3R */
3149 		{111, 63, 16},   /* D2C */
3150 		{ 12, 63, 16},   /* D2L */
3151 		{213, 63, 16},   /* D2R */
3152 		{112, 76, 24}    /* D1C */
3153 	};
3154 
3155 	static int16 rebirthStep1ExplosionCoordinates[7][3] = { // @ G0228_aai_Graphic558_RebirthStep1ExplosionCoordinates
3156 	/* { X, Y, Scale } */
3157 		{112, 53, 15},   /* D3C */
3158 		{ 24, 53, 15},   /* D3L */
3159 		{194, 53, 15},   /* D3R */
3160 		{112, 59, 20},   /* D2C */
3161 		{ 15, 59, 20},   /* D2L */
3162 		{208, 59, 20},   /* D2R */
3163 		{112, 70, 32} /* D1C */
3164 	};
3165 
3166 	static int16 centeredExplosionCoordinates[15][2] = { // @ G0225_aai_Graphic558_CenteredExplosionCoordinates
3167 		/* { X, Y } */
3168 		{111, 47},   /* D4C */
3169 		{ 57, 47},   /* D4L */
3170 		{167, 47},   /* D4R */
3171 		{111, 50},   /* D3C */
3172 		{ 45, 50},   /* D3L */
3173 		{179, 50},   /* D3R */
3174 		{111, 53},   /* D2C */
3175 		{ 20, 53},   /* D2L */
3176 		{205, 53},   /* D2R */
3177 		{111, 57},   /* D1C */
3178 		{-30, 57},   /* D1L */
3179 		{253, 57},   /* D1R */
3180 		{111, 60},   /* D0C */
3181 		{-53, 60},   /* D0L */
3182 		{276, 60}    /* D0R */
3183 	};
3184 
3185 	if (thingParam == _vm->_thingEndOfList)
3186 		return;
3187 
3188 	DungeonMan &dungeon = *_vm->_dungeonMan;
3189 
3190 	int16 orderedViewCellOrdinals = cellOrder;
3191 	Group *group = nullptr;
3192 	Thing groupThing = _vm->_thingNone;
3193 	bool squareHasExplosion = drawCreaturesCompleted = false;
3194 	bool squareHasProjectile = false;
3195 	cellCounter = 0;
3196 	firstThingToDraw = thingParam;
3197 	if (getFlag(orderedViewCellOrdinals, kDMMaskDoorFront)) { /* If the function call is to draw objects on a door square viewed from the front */
3198 		doorFrontViewDrawingPass = (orderedViewCellOrdinals & 0x0001) + 1; /* Two function calls are made in that case to draw objects on both sides of the door frame. The door and its frame are drawn between the two calls. This value indicates the drawing pass so that creatures are drawn in the right order and so that Fluxcages are not drawn twice */
3199 		orderedViewCellOrdinals >>= 4; /* Remove the first nibble that was used for the door front view pass */
3200 	} else
3201 		doorFrontViewDrawingPass = 0; /* The function call is not to draw objects on a door square viewed from the front */
3202 
3203 	remainingViewCellOrdinalsToProcess = orderedViewCellOrdinals;
3204 	L0135_B_DrawAlcoveObjects = !(remainingViewCellOrdinalsToProcess);
3205 	AL_10_viewSquareIndexBackup = viewSquareIndex;
3206 	viewLane = (ViewLane)((viewSquareIndex + 3) % 3);
3207 	bool twoHalfSquareCreaturesFrontView;
3208 	byte *bitmapRedBanana = nullptr;
3209 	byte *bitmapGreenAnt = nullptr;
3210 	do {
3211 		/* Draw objects */
3212 		ActiveGroup *activeGroup = nullptr;
3213 		if (L0135_B_DrawAlcoveObjects) {
3214 			AL_2_viewCell = kDMViewCellAlcove; /* Index of coordinates to draw objects in alcoves */
3215 			cellYellowBear = _vm->returnOppositeDir(directionParam); /* Alcove is on the opposite direction of the viewing direction */
3216 			objectShiftIndex = 2;
3217 		} else {
3218 			AL_2_viewCell = _vm->ordinalToIndex((int16)remainingViewCellOrdinalsToProcess & 0x000F); /* View cell is the index of coordinates to draw object */
3219 			currentViewCellToDraw = AL_2_viewCell;
3220 			remainingViewCellOrdinalsToProcess >>= 4; /* Proceed to the next cell ordinal */
3221 			cellCounter++;
3222 			cellYellowBear = _vm->normalizeModulo4(AL_2_viewCell + directionParam); /* Convert view cell to absolute cell */
3223 			thingParam = firstThingToDraw;
3224 			viewSquareIndex = AL_10_viewSquareIndexBackup; /* Restore value as it may have been modified while drawing a creature */
3225 			objectShiftIndex = 0;
3226 		}
3227 		objectShiftIndex += (cellYellowBear & 0x0001) << 3;
3228 		drawProjectileAsObject = false;
3229 		do {
3230 			AL_4_thingType = thingParam.getType();
3231 			if (AL_4_thingType == kDMThingTypeGroup) {
3232 				groupThing = thingParam;
3233 				continue;
3234 			}
3235 
3236 			if (AL_4_thingType == kDMThingTypeProjectile) {
3237 				squareHasProjectile = true;
3238 				continue;
3239 			}
3240 
3241 			if (AL_4_thingType == kDMThingTypeExplosion) {
3242 				squareHasExplosion = true;
3243 				continue;
3244 			}
3245 
3246 			if ((viewSquareIndex >= kDMViewSquareD3C) && (viewSquareIndex <= kDMViewSquareD0C) && (thingParam.getCell() == cellYellowBear)) { /* Square where objects are visible and object is located on cell being processed */
3247 				objectAspect = &(_objectAspects209[dungeon._objectInfos[dungeon.getObjectInfoIndex(thingParam)]._objectAspectIndex]);
3248 				AL_4_nativeBitmapIndex = kDMGraphicIdxFirstObject + objectAspect->_firstNativeBitmapRelativeIndex;
3249 				useAlcoveObjectImage = (L0135_B_DrawAlcoveObjects && getFlag(objectAspect->_graphicInfo, k0x0010_ObjectAlcoveMask) && (viewLane == kDMViewLaneCenter));
3250 				if (useAlcoveObjectImage)
3251 					AL_4_nativeBitmapIndex++;
3252 
3253 				coordinateSet = objectCoordinateSets[objectAspect->_coordinateSet][viewSquareIndex][AL_2_viewCell];
3254 				if (!coordinateSet[1]) /* If object is not visible */
3255 					continue;
3256 T0115015_DrawProjectileAsObject:
3257 				flipHorizontal = getFlag(objectAspect->_graphicInfo, k0x0001_ObjectFlipOnRightMask) &&
3258 					!useAlcoveObjectImage &&
3259 					((viewLane == kDMViewLaneRight) || ((viewLane == kDMViewLaneCenter) && ((AL_2_viewCell == kDMViewCellFrontRight) || (AL_2_viewCell == kDMViewCellBackRight))));
3260 				/* Flip horizontally if object graphic requires it and is not being drawn in an alcove and the object is either on the right lane or on the right column of the center lane */
3261 				paddingPixelCount = 0;
3262 
3263 				if ((viewSquareIndex == kDMViewSquareD0C) || ((viewSquareIndex >= kDMViewSquareD1C) && (AL_2_viewCell >= kDMViewCellBackRight))) {
3264 					drawingGrabbableObject = ((viewLane == kDMViewLaneCenter) && !drawProjectileAsObject); /* If object is in the center lane (only D0C or D1C with condition above) and is not a projectile */
3265 					AL_8_shiftSetIndex = k0_ShiftSet_D0BackD1Front;
3266 					bitmapRedBanana = getNativeBitmapOrGraphic(AL_4_nativeBitmapIndex); /* Use base graphic, no resizing */
3267 					byteWidth = objectAspect->_byteWidth;
3268 					heightRedEagle = objectAspect->_height;
3269 					if (flipHorizontal) {
3270 						copyBitmapAndFlipHorizontal(bitmapRedBanana, _tmpBitmap, byteWidth, heightRedEagle);
3271 						bitmapRedBanana = _tmpBitmap;
3272 					}
3273 				} else {
3274 					drawingGrabbableObject = false;
3275 					derivedBitmapIndex = kDMDerivedBitmapFirstObject + objectAspect->_firstDerivedBitmapRelativeIndex;
3276 					byte *paletteChanges;
3277 					if ((viewSquareIndex >= kDMViewSquareD1C) || ((viewSquareIndex >= kDMViewSquareD2C) && (AL_2_viewCell >= kDMViewCellBackRight))) {
3278 						derivedBitmapIndex++;
3279 						AL_8_shiftSetIndex = k1_ShiftSet_D1BackD2Front;
3280 						byteWidth = getScaledDimension(objectAspect->_byteWidth, k20_Scale_D2);
3281 						heightRedEagle = getScaledDimension(objectAspect->_height, k20_Scale_D2);
3282 						paletteChanges = _palChangesFloorOrnD2;
3283 					} else {
3284 						AL_8_shiftSetIndex = k2_ShiftSet_D2BackD3Front;
3285 						byteWidth = getScaledDimension(objectAspect->_byteWidth, k16_Scale_D3);
3286 						heightRedEagle = getScaledDimension(objectAspect->_height, k16_Scale_D3);
3287 						paletteChanges = _palChangesFloorOrnD3;
3288 					}
3289 					if (flipHorizontal) {
3290 						derivedBitmapIndex += 2;
3291 						paddingPixelCount = (7 - ((byteWidth - 1) & 0x0007)) << 1;
3292 					} else if (useAlcoveObjectImage)
3293 							derivedBitmapIndex += 4;
3294 
3295 					if (isDerivedBitmapInCache(derivedBitmapIndex))
3296 						bitmapRedBanana = getDerivedBitmap(derivedBitmapIndex);
3297 					else {
3298 						bitmapGreenAnt = getNativeBitmapOrGraphic(AL_4_nativeBitmapIndex);
3299 						bitmapRedBanana = getDerivedBitmap(derivedBitmapIndex);
3300 						blitToBitmapShrinkWithPalChange(bitmapGreenAnt, bitmapRedBanana, objectAspect->_byteWidth << 1, objectAspect->_height, byteWidth << 1, heightRedEagle, paletteChanges);
3301 						if (flipHorizontal)
3302 							flipBitmapHorizontal(bitmapRedBanana, getNormalizedByteWidth(byteWidth), heightRedEagle);
3303 
3304 						addDerivedBitmap(derivedBitmapIndex);
3305 					}
3306 				}
3307 				AL_4_xPos = coordinateSet[0];
3308 				boxByteGreen._rect.bottom = coordinateSet[1];
3309 				if (!drawProjectileAsObject) { /* If drawing an object that is not a projectile */
3310 					AL_4_xPos += shiftSets[AL_8_shiftSetIndex][objectPileShiftSetIndices[objectShiftIndex][0]];
3311 					boxByteGreen._rect.bottom += shiftSets[AL_8_shiftSetIndex][objectPileShiftSetIndices[objectShiftIndex][1]];
3312 					objectShiftIndex++; /* The next object drawn will use the next shift values */
3313 					if (L0135_B_DrawAlcoveObjects) {
3314 						if (objectShiftIndex >= 14)
3315 							objectShiftIndex = 2;
3316 					} else
3317 						objectShiftIndex &= 0x000F;
3318 				}
3319 				boxByteGreen._rect.top = boxByteGreen._rect.bottom - (heightRedEagle - 1);
3320 				if (boxByteGreen._rect.bottom > 135)
3321 					boxByteGreen._rect.bottom = 135;
3322 
3323 				boxByteGreen._rect.right = MIN(223, AL_4_xPos + byteWidth);
3324 				boxByteGreen._rect.left = MAX(0, AL_4_xPos - byteWidth + 1);
3325 				if (boxByteGreen._rect.left) {
3326 					if (flipHorizontal)
3327 						AL_4_xPos = paddingPixelCount;
3328 					else
3329 						AL_4_xPos = 0;
3330 				} else
3331 					AL_4_xPos = byteWidth - AL_4_xPos - 1;
3332 
3333 				if (drawingGrabbableObject) {
3334 					bitmapGreenAnt = bitmapRedBanana;
3335 
3336 					Box *AL_6_box = &dungeon._dungeonViewClickableBoxes[AL_2_viewCell];
3337 
3338 					if (AL_6_box->_rect.left == 255) { /* If the grabbable object is the first */
3339 						*AL_6_box = boxByteGreen;
3340 						heightGreenGoat = AL_6_box->_rect.bottom - AL_6_box->_rect.top;
3341 						if (heightGreenGoat < 14) { /* If the box is too small then enlarge it a little */
3342 							heightGreenGoat = heightGreenGoat >> 1;
3343 							AL_6_box->_rect.top += heightGreenGoat - 7;
3344 							if (heightGreenGoat < 4)
3345 								AL_6_box->_rect.bottom -= heightGreenGoat - 3;
3346 						}
3347 					} else { /* If there are several grabbable objects then enlarge the box so it includes all objects */
3348 						AL_6_box->_rect.left = MIN(AL_6_box->_rect.left, boxByteGreen._rect.left);
3349 						AL_6_box->_rect.right = MAX(AL_6_box->_rect.right, boxByteGreen._rect.right);
3350 						AL_6_box->_rect.top = MIN(AL_6_box->_rect.top, boxByteGreen._rect.top);
3351 						AL_6_box->_rect.bottom = MAX(AL_6_box->_rect.bottom, boxByteGreen._rect.bottom);
3352 					}
3353 					bitmapRedBanana = bitmapGreenAnt;
3354 					dungeon._pileTopObject[AL_2_viewCell] = thingParam; /* The object is at the top of the pile */
3355 				}
3356 				blitToBitmap(bitmapRedBanana, _bitmapViewport, boxByteGreen, AL_4_xPos, 0, getNormalizedByteWidth(byteWidth), k112_byteWidthViewport, kDMColorFlesh, heightRedEagle, k136_heightViewport);
3357 				if (drawProjectileAsObject)
3358 					goto T0115171_BackFromT0115015_DrawProjectileAsObject;
3359 			}
3360 		} while ((thingParam = dungeon.getNextThing(thingParam)) != _vm->_thingEndOfList);
3361 		if (AL_2_viewCell == kDMViewCellAlcove)
3362 			break; /* End of processing when drawing objects in an alcove */
3363 		if (viewSquareIndex < kDMViewSquareD3C)
3364 			break; /* End of processing if square is too far away at D4 */
3365 				   /* Draw creatures */
3366 		drawingLastBackRowCell = ((AL_2_viewCell <= kDMViewCellFrontRight) || (cellCounter == 1)) && (!remainingViewCellOrdinalsToProcess || ((remainingViewCellOrdinalsToProcess & 0x0000000F) >= 3)); /* If (draw cell on the back row or second cell being processed) and (no more cells to draw or next cell to draw is a cell on the front row) */
3367 		if ((groupThing == _vm->_thingNone) || drawCreaturesCompleted)
3368 			goto T0115129_DrawProjectiles; /* Skip code to draw creatures */
3369 
3370 		if (group == nullptr) { /* If all creature data and info has not already been gathered */
3371 			group = (Group *)dungeon.getThingData(groupThing);
3372 			activeGroup = &_vm->_groupMan->_activeGroups[group->getActiveGroupIndex()];
3373 			CreatureInfo *creatureInfo = &dungeon._creatureInfos[group->_type];
3374 			creatureAspectStruct = &_creatureAspects219[creatureInfo->_creatureAspectIndex];
3375 			creatureSize = getFlag(creatureInfo->_attributes, kDMCreatureMaskSize);
3376 			creatureGraphicInfoGreen = creatureInfo->_graphicInfo;
3377 		}
3378 		objectAspect = (ObjectAspect *)creatureAspectStruct;
3379 		AL_0_creatureIndexRed = _vm->_groupMan->getCreatureOrdinalInCell(group, cellYellowBear);
3380 
3381 		if (AL_0_creatureIndexRed) { /* If there is a creature on the cell being processed */
3382 			AL_0_creatureIndexRed--; /* Convert ordinal to index */
3383 			creatureIndexGreen = AL_0_creatureIndexRed;
3384 		} else if (creatureSize == kDMCreatureSizeHalf) {
3385 			AL_0_creatureIndexRed = 0;
3386 			creatureIndexGreen = -1;
3387 		} else
3388 			goto T0115129_DrawProjectiles; /* No creature to draw at cell, skip to projectiles */
3389 
3390 		creatureDirectionDelta = _vm->normalizeModulo4(directionParam - _vm->_groupMan->getCreatureValue(activeGroup->_directions, AL_0_creatureIndexRed));
3391 		twoHalfSquareCreaturesFrontView = false;
3392 		AL_4_groupCells = activeGroup->_cells;
3393 		if (AL_4_groupCells == kDMCreatureTypeSingleCenteredCreature) { /* If there is a single centered creature in the group */
3394 			if (remainingViewCellOrdinalsToProcess || (doorFrontViewDrawingPass == 1))
3395 				goto T0115129_DrawProjectiles; /* Do not draw a single centered creature now, wait until second pass (for a front view door) or until all cells have been drawn so the creature is drawn over all the objects on the floor */
3396 
3397 			drawCreaturesCompleted = true;
3398 			if ((creatureSize == kDMCreatureSizeHalf) && (creatureDirectionDelta & 0x0001)) /* Side view of half square creature */
3399 				AL_2_viewCell = k3_HalfSizedViewCell_CenterColumn;
3400 			else
3401 				AL_2_viewCell = k4_HalfSizedViewCell_FrontRow;
3402 		} else if ((creatureSize == kDMCreatureSizeHalf) && (drawingLastBackRowCell || !remainingViewCellOrdinalsToProcess || (creatureIndexGreen < 0))) {
3403 			if (drawingLastBackRowCell && (doorFrontViewDrawingPass != 2)) {
3404 				if ((creatureIndexGreen >= 0) && (creatureDirectionDelta & 0x0001))
3405 					AL_2_viewCell = k2_HalfSizedViewCell_BackRow; /* Side view of a half square creature on the back row. Drawn during pass 1 for a door square */
3406 				else
3407 					goto T0115129_DrawProjectiles;
3408 			} else if ((doorFrontViewDrawingPass != 1) && !remainingViewCellOrdinalsToProcess) {
3409 				if (creatureDirectionDelta & 0x0001) {
3410 					if (creatureIndexGreen >= 0)
3411 						AL_2_viewCell = k4_HalfSizedViewCell_FrontRow; /* Side view of a half square creature on the front row. Drawn during pass 2 for a door square */
3412 					else
3413 						goto T0115129_DrawProjectiles;
3414 				} else {
3415 					drawCreaturesCompleted = true;
3416 					if (creatureIndexGreen < 0)
3417 						creatureIndexGreen = 0;
3418 
3419 					twoHalfSquareCreaturesFrontView = group->getCount();
3420 					AL_4_groupCells = _vm->_groupMan->getCreatureValue(AL_4_groupCells, AL_0_creatureIndexRed);
3421 					if ((AL_4_groupCells == directionParam) || (AL_4_groupCells == _vm->turnDirLeft(directionParam)))
3422 						AL_2_viewCell = k0_HalfSizedViewCell_LeftColumn;
3423 					else
3424 						AL_2_viewCell = k1_HalfSizedViewCell_RightColumn;
3425 				}
3426 			} else
3427 				goto T0115129_DrawProjectiles;
3428 		} else if (creatureSize != kDMCreatureSizeQuarter)
3429 			goto T0115129_DrawProjectiles;
3430 
3431 		creatureAspectInt = activeGroup->_aspect[creatureIndexGreen];
3432 		if (viewSquareIndex > kDMViewSquareD0C)
3433 			viewSquareIndex--;
3434 
3435 T0115077_DrawSecondHalfSquareCreature:
3436 		coordinateSet = creatureCoordinateSets[((CreatureAspect *)objectAspect)->getCoordSet()][viewSquareIndex][AL_2_viewCell];
3437 		if (!coordinateSet[1])
3438 			goto T0115126_CreatureNotVisible;
3439 		creatureGraphicInfoRed = creatureGraphicInfoGreen;
3440 		AL_4_nativeBitmapIndex = kDMGraphicIdxFirstCreature + ((CreatureAspect *)objectAspect)->_firstNativeBitmapRelativeIndex; /* By default, assume using the front image */
3441 		derivedBitmapIndex = ((CreatureAspect *)objectAspect)->_firstDerivedBitmapIndex;
3442 		int16 sourceByteWidth;
3443 		int16 sourceHeight;
3444 		useCreatureSideBitmap = getFlag(creatureGraphicInfoRed, kDMCreatureMaskSide) && (creatureDirectionDelta & 0x0001);
3445 		if (useCreatureSideBitmap) {
3446 			useCreatureAttackBitmap = useFlippedHorizontallyCreatureFrontImage = useCreatureBackBitmap = false;
3447 			AL_4_nativeBitmapIndex++; /* Skip the front image. Side image is right after the front image */
3448 			derivedBitmapIndex += 2;
3449 			sourceByteWidth = byteWidth = ((CreatureAspect *)objectAspect)->_byteWidthSide;
3450 			sourceHeight = heightRedEagle = ((CreatureAspect *)objectAspect)->_heightSide;
3451 		} else {
3452 			useCreatureBackBitmap = getFlag(creatureGraphicInfoRed, kDMCreatureMaskBack) && (creatureDirectionDelta == 0);
3453 			useCreatureAttackBitmap = !useCreatureBackBitmap;
3454 			if (useCreatureAttackBitmap && getFlag(creatureAspectInt, kDMAspectMaskActiveGroupIsAttacking) && getFlag(creatureGraphicInfoRed, kDMCreatureMaskAttack)) {
3455 				useFlippedHorizontallyCreatureFrontImage = false;
3456 				sourceByteWidth = byteWidth = ((CreatureAspect *)objectAspect)->_byteWidthAttack;
3457 				sourceHeight = heightRedEagle = ((CreatureAspect *)objectAspect)->_heightAttack;
3458 				AL_4_nativeBitmapIndex++; /* Skip the front image */
3459 				derivedBitmapIndex += 2;
3460 				if (getFlag(creatureGraphicInfoRed, kDMCreatureMaskSide)) {
3461 					AL_4_nativeBitmapIndex++; /* If the creature has a side image, it preceeds the attack image */
3462 					derivedBitmapIndex += 2;
3463 				}
3464 
3465 				if (getFlag(creatureGraphicInfoRed, kDMCreatureMaskBack)) {
3466 					AL_4_nativeBitmapIndex++; /* If the creature has a back image, it preceeds the attack image */
3467 					derivedBitmapIndex += 2;
3468 				}
3469 			} else {
3470 				sourceByteWidth = byteWidth = ((CreatureAspect *)objectAspect)->_byteWidthFront;
3471 				sourceHeight = heightRedEagle = ((CreatureAspect *)objectAspect)->_heightFront;
3472 				if (useCreatureBackBitmap) {
3473 					useFlippedHorizontallyCreatureFrontImage = false;
3474 					if (getFlag(creatureGraphicInfoRed, kDMCreatureMaskSide)) {
3475 						AL_4_nativeBitmapIndex += 2; /* If the creature has a side image, it preceeds the back image */
3476 						derivedBitmapIndex += 4;
3477 					} else {
3478 						AL_4_nativeBitmapIndex++; /* If the creature does not have a side image, the back image follows the front image */
3479 						derivedBitmapIndex += 2;
3480 					}
3481 				} else {
3482 					useFlippedHorizontallyCreatureFrontImage = getFlag(creatureGraphicInfoRed, kDMCreatureMaskFlipNonAttack) && getFlag(creatureAspectInt, kDMAspectMaskActiveGroupFlipBitmap);
3483 					if (useFlippedHorizontallyCreatureFrontImage) {
3484 						derivedBitmapIndex += 2;
3485 						if (getFlag(creatureGraphicInfoRed, kDMCreatureMaskSide))
3486 							derivedBitmapIndex += 2;
3487 
3488 						if (getFlag(creatureGraphicInfoRed, kDMCreatureMaskBack))
3489 							derivedBitmapIndex += 2;
3490 
3491 						if (getFlag(creatureGraphicInfoRed, kDMCreatureMaskAttack))
3492 							derivedBitmapIndex += 2;
3493 					}
3494 				}
3495 			}
3496 		}
3497 
3498 		int16 scale;
3499 		if (viewSquareIndex >= kDMViewSquareD1C) { /* Creature is on D1 */
3500 			creaturePaddingPixelCount = 0;
3501 			AL_8_shiftSetIndex = k0_ShiftSet_D0BackD1Front;
3502 			transparentColor = ((CreatureAspect *)objectAspect)->getTranspColour();
3503 			if (useCreatureSideBitmap) {
3504 				bitmapRedBanana = getNativeBitmapOrGraphic(AL_4_nativeBitmapIndex);
3505 				if (creatureDirectionDelta == 1) {
3506 					copyBitmapAndFlipHorizontal(bitmapRedBanana, _tmpBitmap, byteWidth, heightRedEagle);
3507 					bitmapRedBanana = _tmpBitmap;
3508 				}
3509 			} else if (useCreatureBackBitmap || !useFlippedHorizontallyCreatureFrontImage) {
3510 				bitmapRedBanana = getNativeBitmapOrGraphic(AL_4_nativeBitmapIndex);
3511 				if (useCreatureAttackBitmap && getFlag(creatureAspectInt, kDMAspectMaskActiveGroupFlipBitmap)) {
3512 					copyBitmapAndFlipHorizontal(bitmapRedBanana, _tmpBitmap, byteWidth, heightRedEagle);
3513 					bitmapRedBanana = _tmpBitmap;
3514 				}
3515 			} else if (isDerivedBitmapInCache(derivedBitmapIndex)) /* If derived graphic is already in memory */
3516 				bitmapRedBanana = getDerivedBitmap(derivedBitmapIndex);
3517 			else {
3518 				bitmapGreenAnt = getNativeBitmapOrGraphic(AL_4_nativeBitmapIndex);
3519 				if (getFlag(creatureGraphicInfoRed, kDMCreatureMaskFlipNonAttack)) {
3520 					bitmapRedBanana = getDerivedBitmap(derivedBitmapIndex);
3521 					copyBitmapAndFlipHorizontal(bitmapGreenAnt, bitmapRedBanana, byteWidth, heightRedEagle);
3522 				}
3523 				addDerivedBitmap(derivedBitmapIndex);
3524 			}
3525 		} else { /* Creature is on D2 or D3 */
3526 			if (useFlippedHorizontallyCreatureFrontImage)
3527 				derivedBitmapIndex++; /* Skip front D1 image in additional graphics */
3528 
3529 			byte *paletteChanges;
3530 			if (viewSquareIndex >= kDMViewSquareD2C) { /* Creature is on D2 */
3531 				derivedBitmapIndex++; /* Skip front D3 image in additional graphics */
3532 				AL_8_shiftSetIndex = k1_ShiftSet_D1BackD2Front;
3533 				useCreatureSpecialD2FrontBitmap = getFlag(creatureGraphicInfoRed, kDMCreatureMaskSpecialD2Front) && !useCreatureSideBitmap && !useCreatureBackBitmap && !useCreatureAttackBitmap;
3534 				paletteChanges = _palChangesCreatureD2;
3535 				scale = k20_Scale_D2;
3536 			} else { /* Creature is on D3 */
3537 				AL_8_shiftSetIndex = k2_ShiftSet_D2BackD3Front;
3538 				useCreatureSpecialD2FrontBitmap = false;
3539 				paletteChanges = _palChangesCreatureD3;
3540 				scale = k16_Scale_D3;
3541 			}
3542 
3543 			byteWidth = getScaledDimension(sourceByteWidth, scale);
3544 			heightRedEagle = getScaledDimension(sourceHeight, scale);
3545 			transparentColor = paletteChanges[((CreatureAspect *)objectAspect)->getTranspColour()] / 10;
3546 
3547 			bool derivedBitmapInCache = isDerivedBitmapInCache(derivedBitmapIndex);
3548 			if (derivedBitmapInCache)
3549 				bitmapRedBanana = getDerivedBitmap(derivedBitmapIndex);
3550 			else {
3551 				bitmapGreenAnt = getNativeBitmapOrGraphic(AL_4_nativeBitmapIndex);
3552 				bitmapRedBanana = getDerivedBitmap(derivedBitmapIndex);
3553 				blitToBitmapShrinkWithPalChange(bitmapGreenAnt, bitmapRedBanana, sourceByteWidth << 1, sourceHeight, byteWidth << 1, heightRedEagle, paletteChanges);
3554 				addDerivedBitmap(derivedBitmapIndex);
3555 			}
3556 			if ((useCreatureSideBitmap && (creatureDirectionDelta == 1)) || /* If creature is viewed from the right, the side view must be flipped */
3557 				(useCreatureAttackBitmap && getFlag(creatureAspectInt, kDMAspectMaskActiveGroupFlipBitmap)) ||
3558 				(useCreatureSpecialD2FrontBitmap && getFlag(creatureGraphicInfoRed, kDMCreatureMaskSpecialD2FrontIsFlipped)) ||
3559 				(useFlippedHorizontallyCreatureFrontImage && getFlag(creatureGraphicInfoRed, kDMCreatureMaskFlipNonAttack))) { /* If the graphic should be flipped */
3560 				if (!useFlippedHorizontallyCreatureFrontImage || !derivedBitmapInCache) {
3561 					AL_4_normalizdByteWidth = getNormalizedByteWidth(byteWidth);
3562 					if (!useFlippedHorizontallyCreatureFrontImage) {
3563 						memcpy(_tmpBitmap, bitmapRedBanana, sizeof(byte) * AL_4_normalizdByteWidth * heightRedEagle);
3564 						bitmapRedBanana = _tmpBitmap;
3565 					}
3566 					flipBitmapHorizontal(bitmapRedBanana, AL_4_normalizdByteWidth, heightRedEagle);
3567 				}
3568 				creaturePaddingPixelCount = (7 - ((byteWidth - 1) & 0x0007)) << 1;
3569 			} else
3570 				creaturePaddingPixelCount = 0;
3571 		}
3572 		AL_4_yPos = coordinateSet[1];
3573 		AL_4_yPos += shiftSets[AL_8_shiftSetIndex][getVerticalOffsetM23(creatureAspectInt)];
3574 		boxByteGreen._rect.bottom = MIN(AL_4_yPos, (int16)135);
3575 		boxByteGreen._rect.top = MAX(0, AL_4_yPos - (heightRedEagle - 1));
3576 		AL_4_xPos = coordinateSet[0];
3577 		AL_4_xPos += shiftSets[AL_8_shiftSetIndex][getHorizontalOffsetM22(creatureAspectInt)];
3578 
3579 		if (viewLane == kDMViewLaneLeft)
3580 			AL_4_xPos -= 100;
3581 		else if (viewLane != kDMViewLaneCenter) /* Lane right */
3582 			AL_4_xPos += 100;
3583 
3584 		boxByteGreen._rect.right = CLIP(0, AL_4_xPos + byteWidth, 223);
3585 
3586 		if (!boxByteGreen._rect.right)
3587 			goto T0115126_CreatureNotVisible;
3588 		int16 AL_0_creaturePosX;
3589 		boxByteGreen._rect.left = CLIP(0, AL_4_xPos - byteWidth + 1, 223);
3590 		if (boxByteGreen._rect.left) {
3591 			if (boxByteGreen._rect.left == 223)
3592 				goto T0115126_CreatureNotVisible;
3593 			AL_0_creaturePosX = creaturePaddingPixelCount;
3594 		} else
3595 			AL_0_creaturePosX = creaturePaddingPixelCount + (byteWidth - AL_4_xPos - 1);
3596 
3597 		blitToBitmap(bitmapRedBanana, _bitmapViewport, boxByteGreen, AL_0_creaturePosX, 0, getNormalizedByteWidth(byteWidth), k112_byteWidthViewport, (Color)transparentColor, heightRedEagle, 136);
3598 T0115126_CreatureNotVisible:
3599 		if (twoHalfSquareCreaturesFrontView) {
3600 			twoHalfSquareCreaturesFrontView = false;
3601 			creatureAspectInt = activeGroup->_aspect[!creatureIndexGreen]; /* Aspect of the other creature in the pair */
3602 			if (AL_2_viewCell == k1_HalfSizedViewCell_RightColumn)
3603 				AL_2_viewCell = k0_HalfSizedViewCell_LeftColumn;
3604 			else
3605 				AL_2_viewCell = k1_HalfSizedViewCell_RightColumn;
3606 
3607 			goto T0115077_DrawSecondHalfSquareCreature;
3608 		}
3609 		/* Draw projectiles */
3610 T0115129_DrawProjectiles:
3611 		//If there is no projectile to draw or if projectiles are not visible on the specified square or on the cell being drawn
3612 		if (!squareHasProjectile)
3613 			continue;
3614 		viewSquareIndex = AL_10_viewSquareIndexBackup;
3615 		if (viewSquareIndex > kDMViewSquareD0C)
3616 			continue;
3617 		AL_2_viewCell = currentViewCellToDraw;
3618 		projectilePosX = objectCoordinateSets[0][viewSquareIndex][AL_2_viewCell][0];
3619 		if (!projectilePosX) /* If there is no projectile to draw or if projectiles are not visible on the specified square or on the cell being drawn */
3620 			continue;
3621 
3622 		thingParam = firstThingToDraw; /* Restart processing list of objects from the beginning. The next loop draws only projectile objects among the list */
3623 		do {
3624 			if ((thingParam.getType() == kDMThingTypeProjectile) && (thingParam.getCell() == cellYellowBear)) {
3625 				Projectile *projectile = (Projectile *)dungeon.getThingData(thingParam);
3626 				AL_4_projectileAspect = dungeon.getProjectileAspect(projectile->_slot);
3627 				if (AL_4_projectileAspect < 0) { /* Negative value: projectile aspect is the ordinal of a PROJECTIL_ASPECT */
3628 					objectAspect = (ObjectAspect *)&_projectileAspect[_vm->ordinalToIndex(-AL_4_projectileAspect)];
3629 					AL_4_nativeBitmapIndex = ((ProjectileAspect *)objectAspect)->_firstNativeBitmapRelativeIndex + kDMGraphicIdxFirstProjectile;
3630 					projectileAspectType = getFlag(((ProjectileAspect *)objectAspect)->_graphicInfo, k0x0003_ProjectileAspectTypeMask);
3631 
3632 					bool doNotScaleWithKineticEnergy = !getFlag(((ProjectileAspect *)objectAspect)->_graphicInfo, k0x0100_ProjectileScaleWithKineticEnergyMask);
3633 					if ((doNotScaleWithKineticEnergy || (projectile->_kineticEnergy == 255)) && (viewSquareIndex == kDMViewSquareD0C)) {
3634 						scale = 0; /* Use native bitmap without resizing */
3635 						byteWidth = ((ProjectileAspect *)objectAspect)->_byteWidth;
3636 						heightRedEagle = ((ProjectileAspect *)objectAspect)->_height;
3637 					} else {
3638 						AL_8_projectileScaleIndex = ((viewSquareIndex / 3) << 1) + (AL_2_viewCell >> 1);
3639 						scale = _projectileScales[AL_8_projectileScaleIndex];
3640 						if (!doNotScaleWithKineticEnergy) {
3641 							scale = (scale * MAX(96, projectile->_kineticEnergy + 1)) >> 8;
3642 						}
3643 						byteWidth = getScaledDimension(((ProjectileAspect *)objectAspect)->_byteWidth, scale);
3644 						heightRedEagle = getScaledDimension(((ProjectileAspect *)objectAspect)->_height, scale);
3645 					}
3646 					bool projectileAspectTypeHasBackGraphicAndRotation = (projectileAspectType == k0_ProjectileAspectHasBackGraphicRotation);
3647 					if (projectileAspectTypeHasBackGraphicAndRotation)
3648 						projectileFlipVertical = ((mapXpos + mapYpos) & 0x0001);
3649 
3650 					bool flipVertical;
3651 					if (projectileAspectType == k3_ProjectileAspectHasNone) {
3652 						projectileBitmapIndexDelta = 0;
3653 						flipVertical = flipHorizontal = false;
3654 					} else if (_vm->isOrientedWestEast(Direction(projectileDirection = _vm->_timeline->_events[projectile->_eventIndex]._Cu._projectile.getDir())) != _vm->isOrientedWestEast(directionParam)) {
3655 						if (projectileAspectType == k2_ProjectileAspectHasRotation)
3656 							projectileBitmapIndexDelta = 1;
3657 						else
3658 							projectileBitmapIndexDelta = 2;
3659 
3660 						if (projectileAspectTypeHasBackGraphicAndRotation) {
3661 							flipHorizontal = (AL_2_viewCell == kDMViewCellFronLeft) || (AL_2_viewCell == kDMViewCellBackLeft);
3662 							flipVertical = projectileFlipVertical;
3663 							if (!flipVertical)
3664 								flipHorizontal = !flipHorizontal;
3665 						} else {
3666 							flipVertical = false;
3667 							flipHorizontal = (_vm->turnDirRight(directionParam) == projectileDirection);
3668 						}
3669 					} else {
3670 						if ((projectileAspectType >= k2_ProjectileAspectHasRotation) || ((projectileAspectType == k1_ProjectileAspectBackGraphic) && (projectileDirection != directionParam)) || (projectileAspectTypeHasBackGraphicAndRotation && projectileFlipVertical)) /* If the projectile does not have a back graphic or has one but is not seen from the back or if it has a back graphic and rotation and should be flipped vertically */
3671 							projectileBitmapIndexDelta = 0;
3672 						else
3673 							projectileBitmapIndexDelta = 1;
3674 
3675 						flipVertical = projectileAspectTypeHasBackGraphicAndRotation && (AL_2_viewCell < kDMViewCellBackRight);
3676 						flipHorizontal = getFlag(((ProjectileAspect *)objectAspect)->_graphicInfo, k0x0010_ProjectileSideMask) && !((viewLane == kDMViewLaneRight) || ((viewLane == kDMViewLaneCenter) && ((AL_2_viewCell == kDMViewCellFrontRight) || (AL_2_viewCell == kDMViewCellBackRight))));
3677 					}
3678 
3679 					AL_4_nativeBitmapIndex += projectileBitmapIndexDelta;
3680 					paddingPixelCount = 0;
3681 					if (!scale) {
3682 						bitmapRedBanana = getNativeBitmapOrGraphic(AL_4_nativeBitmapIndex);
3683 					} else {
3684 						if (flipHorizontal)
3685 							paddingPixelCount = (7 - ((byteWidth - 1) & 0x0007)) << 1;
3686 
3687 						derivedBitmapIndex = kDMDerivedBitmapFirstProjectile + ((ProjectileAspect *)objectAspect)->_firstDerivedBitmapRelativeIndex + (projectileBitmapIndexDelta * 6) + AL_8_projectileScaleIndex;
3688 						if (doNotScaleWithKineticEnergy && isDerivedBitmapInCache(derivedBitmapIndex)) {
3689 							bitmapRedBanana = getDerivedBitmap(derivedBitmapIndex);
3690 						} else {
3691 							bitmapGreenAnt = getNativeBitmapOrGraphic(AL_4_nativeBitmapIndex);
3692 							if (doNotScaleWithKineticEnergy)
3693 								bitmapRedBanana = getDerivedBitmap(derivedBitmapIndex);
3694 							else
3695 								bitmapRedBanana = _tmpBitmap;
3696 
3697 							blitToBitmapShrinkWithPalChange(bitmapGreenAnt, bitmapRedBanana, ((ProjectileAspect *)objectAspect)->_byteWidth << 1, ((ProjectileAspect *)objectAspect)->_height, byteWidth << 1, heightRedEagle, _palChangesProjectile[AL_8_projectileScaleIndex >> 1]);
3698 							if (doNotScaleWithKineticEnergy) {
3699 								addDerivedBitmap(derivedBitmapIndex);
3700 							}
3701 						}
3702 					}
3703 					if (flipHorizontal || flipVertical) {
3704 						AL_4_normalizdByteWidth = getNormalizedByteWidth(byteWidth);
3705 						if (bitmapRedBanana != _tmpBitmap) {
3706 							memcpy(_tmpBitmap, bitmapRedBanana, sizeof(byte) * AL_4_normalizdByteWidth * heightRedEagle);
3707 							bitmapRedBanana = _tmpBitmap;
3708 						}
3709 						if (flipVertical)
3710 							flipBitmapVertical(bitmapRedBanana, AL_4_normalizdByteWidth, heightRedEagle);
3711 
3712 						if (flipHorizontal)
3713 							flipBitmapHorizontal(bitmapRedBanana, AL_4_normalizdByteWidth, heightRedEagle);
3714 					}
3715 					boxByteGreen._rect.bottom = (heightRedEagle >> 1) + 47;
3716 					boxByteGreen._rect.top = 47 - (heightRedEagle >> 1) + !(heightRedEagle & 0x0001);
3717 					boxByteGreen._rect.right = MIN(223, projectilePosX + byteWidth);
3718 					boxByteGreen._rect.left = MAX(0, projectilePosX - byteWidth + 1);
3719 					if (boxByteGreen._rect.left) {
3720 						if (flipHorizontal)
3721 							AL_4_xPos = paddingPixelCount;
3722 						else
3723 							AL_4_xPos = 0;
3724 					} else
3725 						AL_4_xPos = MAX(paddingPixelCount, int16(byteWidth - projectilePosX - 1)); /* BUG0_06 Graphical glitch when drawing projectiles or explosions. If a projectile or explosion bitmap is cropped because it is only partly visible on the left side of the viewport (boxByteGreen.X1 = 0) and the bitmap is flipped horizontally (flipHorizontal = true) then a wrong part of the bitmap is drawn on screen. To fix this bug, "+ paddingPixelCount" must be added to the second parameter of this function call */
3726 
3727 					blitToBitmap(bitmapRedBanana, _bitmapViewport, boxByteGreen, AL_4_xPos, 0, getNormalizedByteWidth(byteWidth), k112_byteWidthViewport, kDMColorFlesh, heightRedEagle, k136_heightViewport);
3728 				} else { /* Positive value: projectile aspect is the index of a OBJECT_ASPECT */
3729 					useAlcoveObjectImage = false;
3730 					byte projectileCoordinates[2];
3731 					projectileCoordinates[0] = projectilePosX;
3732 					projectileCoordinates[1] = 47;
3733 					coordinateSet = projectileCoordinates;
3734 					objectAspect = &_objectAspects209[AL_4_projectileAspect];
3735 					AL_4_nativeBitmapIndex = objectAspect->_firstNativeBitmapRelativeIndex + kDMGraphicIdxFirstObject;
3736 					drawProjectileAsObject = true;
3737 					goto T0115015_DrawProjectileAsObject; /* Go to code section to draw an object. Once completed, it jumps back to T0115171_BackFromT0115015_DrawProjectileAsObject below */
3738 				}
3739 			}
3740 T0115171_BackFromT0115015_DrawProjectileAsObject:;
3741 		} while ((thingParam = dungeon.getNextThing(thingParam)) != _vm->_thingEndOfList);
3742 	} while (remainingViewCellOrdinalsToProcess);
3743 
3744 	/* Draw explosions */
3745 	if (!squareHasExplosion)
3746 		return;
3747 
3748 	Explosion *fluxcageExplosion = nullptr;
3749 	int16 *explosionCoordinates;
3750 
3751 	AL_1_viewSquareExplosionIndex = AL_10_viewSquareIndexBackup + 3; /* Convert square index to square index for explosions */
3752 	AL_10_explosionScaleIndex = AL_1_viewSquareExplosionIndex / 3;
3753 	thingParam = firstThingToDraw; /* Restart processing list of things from the beginning. The next loop draws only explosion things among the list */
3754 	do {
3755 		if (thingParam.getType() == kDMThingTypeExplosion) {
3756 			AL_2_cellPurpleMan = thingParam.getCell();
3757 			Explosion *explosion = (Explosion *)dungeon.getThingData(thingParam);
3758 			AL_4_explosionType = explosion->getType();
3759 			bool rebirthExplosion = ((uint16)AL_4_explosionType >= kDMExplosionTypeRebirthStep1);
3760 			if (rebirthExplosion && ((AL_1_viewSquareExplosionIndex < kDMViewSquareD3CExplosion) || (AL_1_viewSquareExplosionIndex > kDMViewSquareD1CExplosion) || (AL_2_cellPurpleMan != cellYellowBear))) /* If explosion is rebirth and is not visible */
3761 				continue;
3762 			bool smoke = false;
3763 			if ((AL_4_explosionType == kDMExplosionTypeFireball) || (AL_4_explosionType == kDMExplosionTypeLightningBolt) || (AL_4_explosionType == kDMExplosionTypeRebirthStep2)) {
3764 				AL_4_explosionAspectIndex = kDMExplosionAspectFire;
3765 			} else {
3766 				if ((AL_4_explosionType == kDMExplosionTypePoisonBolt) || (AL_4_explosionType == kDMExplosionTypePoisonCloud)) {
3767 					AL_4_explosionAspectIndex = kDMExplosionAspectPoison;
3768 				} else if (AL_4_explosionType == kDMExplosionTypeSmoke) {
3769 					smoke = true;
3770 					AL_4_explosionAspectIndex = kDMExplosionAspectSmoke;
3771 				} else {
3772 					if (AL_4_explosionType == kDMExplosionTypeRebirthStep1) {
3773 						objectAspect = (ObjectAspect *)&_projectileAspect[_vm->ordinalToIndex(-dungeon.getProjectileAspect(_vm->_thingExplLightningBolt))];
3774 						bitmapRedBanana = getNativeBitmapOrGraphic(((ProjectileAspect *)objectAspect)->_firstNativeBitmapRelativeIndex + (kDMGraphicIdxFirstProjectile + 1));
3775 						explosionCoordinates = rebirthStep1ExplosionCoordinates[AL_1_viewSquareExplosionIndex - 3];
3776 						byteWidth = getScaledDimension((((ProjectileAspect *)objectAspect)->_byteWidth), explosionCoordinates[2]);
3777 						heightRedEagle = getScaledDimension((((ProjectileAspect *)objectAspect)->_height), explosionCoordinates[2]);
3778 						if (AL_1_viewSquareExplosionIndex != kDMViewSquareD1CExplosion) {
3779 							blitToBitmapShrinkWithPalChange(bitmapRedBanana, _tmpBitmap, ((ProjectileAspect *)objectAspect)->_byteWidth << 1, ((ProjectileAspect *)objectAspect)->_height, byteWidth << 1, heightRedEagle, _palChangesNoChanges);
3780 							bitmapRedBanana = _tmpBitmap;
3781 						}
3782 						goto T0115200_DrawExplosion;
3783 					}
3784 					if (AL_4_explosionType == kDMExplosionTypeFluxcage) {
3785 						if (AL_1_viewSquareExplosionIndex >= kDMViewSquareD3LExplosion)
3786 							fluxcageExplosion = explosion;
3787 						continue;
3788 					}
3789 					AL_4_explosionAspectIndex = kDMExplosionAspectSpell;
3790 				}
3791 			}
3792 			if (AL_1_viewSquareExplosionIndex == kDMViewSquareD0CExplosion) {
3793 				if (smoke)
3794 					AL_4_explosionAspectIndex--; /* Smoke uses the same graphics as Poison Cloud, but with palette changes */
3795 
3796 				AL_4_explosionAspectIndex = AL_4_explosionAspectIndex * 3; /* 3 graphics per explosion pattern */
3797 				AL_2_explosionSize = (explosion->getAttack() >> 5);
3798 				if (AL_2_explosionSize) {
3799 					AL_4_explosionAspectIndex++; /* Use second graphic in the pattern for medium explosion attack */
3800 					if (AL_2_explosionSize > 3)
3801 						AL_4_explosionAspectIndex++; /* Use third graphic in the pattern for large explosion attack */
3802 				}
3803 				isDerivedBitmapInCache(kDMDerivedBitmapViewport);
3804 				bitmapRedBanana = getNativeBitmapOrGraphic(AL_4_explosionAspectIndex + kDMGraphicIdxFirstExplosionPattern);
3805 				if (smoke) {
3806 					blitToBitmapShrinkWithPalChange(bitmapRedBanana, _tmpBitmap, 48, 32, 48, 32, _palChangeSmoke);
3807 					bitmapRedBanana = _tmpBitmap;
3808 				}
3809 				blitBoxFilledWithMaskedBitmap(bitmapRedBanana, _bitmapViewport, 0, getDerivedBitmap(kDMDerivedBitmapViewport), boxExplosionPatternD0C, _vm->getRandomNumber(4) + 87, _vm->getRandomNumber(64), k112_byteWidthViewport, Color(k0x0080_BlitDoNotUseMask | kDMColorFlesh), 0, 0, 136, 93);
3810 				addDerivedBitmap(kDMDerivedBitmapViewport);
3811 				warning("DISABLED CODE: f480_releaseBlock in drawObjectsCreaturesProjectilesExplosions");
3812 				//f480_releaseBlock(k0_DerivedBitmapViewport | 0x8000);
3813 			} else {
3814 				int16 explosionScale;
3815 				if (rebirthExplosion) {
3816 					explosionCoordinates = rebirthStep2ExplosionCoordinates[AL_1_viewSquareExplosionIndex - 3];
3817 					explosionScale = explosionCoordinates[2];
3818 				} else {
3819 					if (explosion->getCentered()) {
3820 						explosionCoordinates = centeredExplosionCoordinates[AL_1_viewSquareExplosionIndex];
3821 					} else {
3822 						if ((AL_2_cellPurpleMan == directionParam) || (AL_2_cellPurpleMan == _vm->turnDirLeft(directionParam)))
3823 							AL_2_viewCell = kDMViewCellFronLeft;
3824 						else
3825 							AL_2_viewCell = kDMViewCellFrontRight;
3826 
3827 						explosionCoordinates = explosionCoordinatesArray[AL_1_viewSquareExplosionIndex][AL_2_viewCell];
3828 					}
3829 					explosionScale = MAX(4, (MAX(48, explosion->getAttack() + 1) * explosionBaseScales[AL_10_explosionScaleIndex]) >> 8) & (int)0xFFFE;
3830 				}
3831 				bitmapRedBanana = getExplosionBitmap(AL_4_explosionAspectIndex, explosionScale, byteWidth, heightRedEagle);
3832 T0115200_DrawExplosion:
3833 				bool flipVertical = _vm->getRandomNumber(2);
3834 				paddingPixelCount = 0;
3835 				flipHorizontal = _vm->getRandomNumber(2);
3836 				if (flipHorizontal)
3837 					paddingPixelCount = (7 - ((byteWidth - 1) & 0x0007)) << 1; /* Number of unused pixels in the units on the right of the bitmap */
3838 
3839 				boxByteGreen._rect.bottom = MIN(135, explosionCoordinates[1] + (heightRedEagle >> 1));
3840 				AL_4_yPos = MAX(0, explosionCoordinates[1] - (heightRedEagle >> 1) + !(heightRedEagle & 0x0001));
3841 				if (AL_4_yPos >= 136)
3842 					continue;
3843 				boxByteGreen._rect.top = AL_4_yPos;
3844 				AL_4_xPos = MIN(223, explosionCoordinates[0] + byteWidth);
3845 				if (AL_4_xPos < 0)
3846 					continue;
3847 				boxByteGreen._rect.right = AL_4_xPos;
3848 				AL_4_xPos = explosionCoordinates[0];
3849 				boxByteGreen._rect.left = CLIP(0, AL_4_xPos - byteWidth + 1, 223);
3850 
3851 				if (boxByteGreen._rect.left)
3852 					AL_4_xPos = paddingPixelCount;
3853 				else {
3854 					AL_4_xPos = MAX(paddingPixelCount, int16(byteWidth - AL_4_xPos - 1)); /* BUG0_07 Graphical glitch when drawing explosions. If an explosion bitmap is cropped because it is only partly visible on the left side of the viewport (boxByteGreen.X1 = 0) and the bitmap is not flipped horizontally (flipHorizontal = false) then the variable paddingPixelCount is not set before being used here. Its previous value (defined while drawing something else) is used and may cause an incorrect bitmap to be drawn */
3855 
3856 																				   /* BUG0_06 Graphical glitch when drawing projectiles or explosions. If a projectile or explosion bitmap is cropped because it is only partly visible on the left side of the viewport (boxByteGreen.X1 = 0) and the bitmap is flipped horizontally (flipHorizontal = true) then a wrong part of the bitmap is drawn on screen. To fix this bug, "+ paddingPixelCount" must be added to the second parameter of this function call */
3857 				}
3858 
3859 				if (boxByteGreen._rect.right <= boxByteGreen._rect.left)
3860 					continue;
3861 
3862 				byteWidth = getNormalizedByteWidth(byteWidth);
3863 				if (flipHorizontal || flipVertical) {
3864 					memcpy(_tmpBitmap, bitmapRedBanana, sizeof(byte) * byteWidth * heightRedEagle);
3865 					bitmapRedBanana = _tmpBitmap;
3866 				}
3867 
3868 				if (flipHorizontal)
3869 					flipBitmapHorizontal(bitmapRedBanana, byteWidth, heightRedEagle);
3870 
3871 				if (flipVertical)
3872 					flipBitmapVertical(bitmapRedBanana, byteWidth, heightRedEagle);
3873 
3874 				blitToBitmap(bitmapRedBanana, _bitmapViewport, boxByteGreen, AL_4_xPos, 0, byteWidth, k112_byteWidthViewport, kDMColorFlesh, heightRedEagle, k136_heightViewport);
3875 			}
3876 		}
3877 	} while ((thingParam = dungeon.getNextThing(thingParam))!= _vm->_thingEndOfList);
3878 
3879 	if ((fluxcageExplosion != 0) && (doorFrontViewDrawingPass != 1) && !_doNotDrawFluxcagesDuringEndgame) { /* Fluxcage is an explosion displayed as a field (like teleporters), above all other graphics */
3880 		AL_1_viewSquareExplosionIndex -= 3; /* Convert square index for explosions back to square index */
3881 		FieldAspect fieldAspect = _fieldAspects188[viewSquareIndex];
3882 		(fieldAspect._nativeBitmapRelativeIndex)++; /* NativeBitmapRelativeIndex is now the index of the Fluxcage field graphic */
3883 		drawField(&fieldAspect, _frameWalls163[viewSquareIndex]._box);
3884 	}
3885 }
3886 
getNormalizedByteWidth(uint16 byteWidth)3887 uint16 DisplayMan::getNormalizedByteWidth(uint16 byteWidth) {
3888 	return (byteWidth + 7) & 0xFFF8;
3889 }
3890 
getVerticalOffsetM23(uint16 val)3891 uint16 DisplayMan::getVerticalOffsetM23(uint16 val) {
3892 	return (val >> 3) & 0x7;
3893 }
3894 
getHorizontalOffsetM22(uint16 val)3895 uint16 DisplayMan::getHorizontalOffsetM22(uint16 val) {
3896 	return (val & 0x7);
3897 }
3898 
isDerivedBitmapInCache(int16 derivedBitmapIndex)3899 bool DisplayMan::isDerivedBitmapInCache(int16 derivedBitmapIndex) {
3900 	if (_derivedBitmaps[derivedBitmapIndex] == nullptr) {
3901 		// * 2, because the original uses 4 bits instead of 8 bits to store a pixel
3902 		_derivedBitmaps[derivedBitmapIndex] = new byte[_derivedBitmapByteCount[derivedBitmapIndex] * 2 + 16];
3903 		return false;
3904 	}
3905 
3906 	return true;
3907 }
3908 
getDerivedBitmap(int16 derivedBitmapIndex)3909 byte *DisplayMan::getDerivedBitmap(int16 derivedBitmapIndex) {
3910 	return _derivedBitmaps[derivedBitmapIndex];
3911 }
3912 
addDerivedBitmap(int16 derivedBitmapIndex)3913 void DisplayMan::addDerivedBitmap(int16 derivedBitmapIndex) {}
3914 
releaseBlock(uint16 index)3915 void DisplayMan::releaseBlock(uint16 index) {
3916 	index &= ~0x8000;
3917 	delete[] _derivedBitmaps[index];
3918 	_derivedBitmaps[index] = nullptr;
3919 }
3920 
getDarkenedColor(uint16 RGBcolor)3921 uint16 DisplayMan::getDarkenedColor(uint16 RGBcolor) {
3922 	if (getFlag(RGBcolor, D12_MASK_BLUE_COMPONENT))
3923 		RGBcolor--;
3924 
3925 	if (getFlag(RGBcolor, D11_MASK_GREEN_COMPONENT))
3926 		RGBcolor -= 16;
3927 
3928 	if (getFlag(RGBcolor, D10_MASK_RED_COMPONENT))
3929 		RGBcolor -= 256;
3930 
3931 	return RGBcolor;
3932 }
3933 
startEndFadeToPalette(uint16 * P0849_pui_Palette)3934 void DisplayMan::startEndFadeToPalette(uint16 *P0849_pui_Palette) {
3935 	uint16 *paletteRegister = _paletteFadeTemporary;
3936 
3937 	for (int16 i = 0; i < 16; i++)
3938 		paletteRegister[i] = _paletteFadeFrom[i];
3939 
3940 	for (int16 i = 0; i < 8; i++) {
3941 		paletteRegister = _paletteFadeTemporary;
3942 		for (int16 colIdx = 0; colIdx < 16; colIdx++, paletteRegister++) {
3943 			uint16 currentRGBColor = getFlag(*paletteRegister, D12_MASK_BLUE_COMPONENT);
3944 			int16 targetRGBColor = getFlag(P0849_pui_Palette[colIdx], D12_MASK_BLUE_COMPONENT);
3945 			if (currentRGBColor > targetRGBColor) {
3946 				if (currentRGBColor > targetRGBColor + 1)
3947 					*paletteRegister -= 2;
3948 				else
3949 					*paletteRegister -= 1;
3950 			} else if (currentRGBColor < targetRGBColor) {
3951 				if (currentRGBColor < targetRGBColor - 1)
3952 					*paletteRegister += 2;
3953 				else
3954 					*paletteRegister += 1;
3955 			}
3956 			currentRGBColor = getFlag(*paletteRegister, D11_MASK_GREEN_COMPONENT) >> 4;
3957 			targetRGBColor = getFlag(P0849_pui_Palette[colIdx], D11_MASK_GREEN_COMPONENT) >> 4;
3958 			if (currentRGBColor > targetRGBColor) {
3959 				if (currentRGBColor > targetRGBColor + 1)
3960 					*paletteRegister -= 32;
3961 				else
3962 					*paletteRegister -= 16;
3963 			} else if (currentRGBColor < targetRGBColor) {
3964 				if (currentRGBColor < targetRGBColor - 1)
3965 					*paletteRegister += 32;
3966 				else
3967 					*paletteRegister += 16;
3968 			}
3969 			currentRGBColor = getFlag(*paletteRegister, D10_MASK_RED_COMPONENT) >> 8;
3970 			targetRGBColor = getFlag(P0849_pui_Palette[colIdx], D10_MASK_RED_COMPONENT) >> 8;
3971 			if (currentRGBColor > targetRGBColor) {
3972 				if (currentRGBColor > targetRGBColor + 1)
3973 					*paletteRegister -= 512;
3974 				else
3975 					*paletteRegister -= 256;
3976 			} else if (currentRGBColor < targetRGBColor) {
3977 				if (currentRGBColor < targetRGBColor - 1)
3978 					*paletteRegister += 512;
3979 				else
3980 					*paletteRegister += 256;
3981 			}
3982 		}
3983 		_vm->delay(1);
3984 		_vm->_eventMan->discardAllInput();
3985 		buildPaletteChangeCopperList(_paletteFadeTemporary, _paletteFadeTemporary);
3986 	}
3987 }
3988 
buildPaletteChangeCopperList(uint16 * middleScreen,uint16 * topAndBottom)3989 void DisplayMan::buildPaletteChangeCopperList(uint16 *middleScreen, uint16 *topAndBottom) {
3990 	_paletteFadeFrom = topAndBottom;
3991 	byte colorPalette[32 * 3];
3992 	for (int i = 0; i < 16; ++i) {
3993 		colorPalette[i * 3] = (topAndBottom[i] >> 8) * (256 / 16);
3994 		colorPalette[i * 3 + 1] = (topAndBottom[i] >> 4) * (256 / 16);
3995 		colorPalette[i * 3 + 2] = topAndBottom[i] * (256 / 16);
3996 	}
3997 	for (int i = 16; i < 32; ++i) {
3998 		colorPalette[i * 3] = (middleScreen[i - 16] >> 8) * (256 / 16);
3999 		colorPalette[i * 3 + 1] = (middleScreen[i - 16] >> 4) * (256 / 16);
4000 		colorPalette[i * 3 + 2] = middleScreen[i - 16] * (256 / 16);
4001 	}
4002 	g_system->getPaletteManager()->setPalette(colorPalette, 0, 32);
4003 }
4004 
4005 }
4006