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 _vm->_console->onFrame();
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