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 #include "kyra/engine/eob.h"
24 #include "kyra/resource/resource.h"
25 #include "kyra/sound/sound_intern.h"
26 
27 #include "common/memstream.h"
28 
29 
30 namespace Kyra {
31 
32 #ifdef ENABLE_EOB
loadEoB2SeqData(int id,int & entries)33 const DarkMoonAnimCommand *StaticResource::loadEoB2SeqData(int id, int &entries) {
34 	return (const DarkMoonAnimCommand *)getData(id, kEoB2SequenceData, entries);
35 }
36 
loadEoB2ShapeData(int id,int & entries)37 const DarkMoonShapeDef *StaticResource::loadEoB2ShapeData(int id, int &entries) {
38 	return (const DarkMoonShapeDef *)getData(id, kEoB2ShapeData, entries);
39 }
40 
loadEoBNpcData(int id,int & entries)41 const EoBCharacter *StaticResource::loadEoBNpcData(int id, int &entries) {
42 	return (const EoBCharacter *)getData(id, kEoBNpcData, entries);
43 }
44 
loadEoB2SeqData(Common::SeekableReadStream & stream,void * & ptr,int & size)45 bool StaticResource::loadEoB2SeqData(Common::SeekableReadStream &stream, void *&ptr, int &size) {
46 	size = stream.size() / 11;
47 
48 	DarkMoonAnimCommand *s = new DarkMoonAnimCommand[size];
49 
50 	for (int i = 0; i < size; i++) {
51 		s[i].command = stream.readByte();
52 		s[i].obj = stream.readByte();
53 		s[i].x1 = stream.readSint16BE();
54 		s[i].y1 = stream.readByte();
55 		s[i].delay = stream.readByte();
56 		s[i].pal = stream.readByte();
57 		s[i].x2 = stream.readByte();
58 		s[i].y2 = stream.readByte();
59 		s[i].w = stream.readByte();
60 		s[i].h = stream.readByte();
61 	}
62 
63 	ptr = s;
64 	return true;
65 }
66 
loadEoB2ShapeData(Common::SeekableReadStream & stream,void * & ptr,int & size)67 bool StaticResource::loadEoB2ShapeData(Common::SeekableReadStream &stream, void *&ptr, int &size) {
68 	size = stream.size() / 6;
69 
70 	DarkMoonShapeDef *s = new DarkMoonShapeDef[size];
71 
72 	for (int i = 0; i < size; i++) {
73 		s[i].index = stream.readSint16BE();
74 		s[i].x = stream.readByte();
75 		s[i].y = stream.readByte();
76 		s[i].w = stream.readByte();
77 		s[i].h = stream.readByte();
78 	}
79 
80 	ptr = s;
81 	return true;
82 }
83 
loadEoBNpcData(Common::SeekableReadStream & stream,void * & ptr,int & size)84 bool StaticResource::loadEoBNpcData(Common::SeekableReadStream &stream, void *&ptr, int &size) {
85 	size = stream.readUint16BE();
86 
87 	EoBCharacter *e = new EoBCharacter[size];
88 	memset(e, 0, size * sizeof(EoBCharacter));
89 	EoBCharacter *s = e;
90 
91 	for (int i = 0; i < size; i++, s++) {
92 		s->id = stream.readByte();
93 		s->flags = stream.readByte();
94 		s->name[0] = 0;
95 		s->strengthCur = stream.readSByte();
96 		s->strengthMax = stream.readSByte();
97 		s->strengthExtCur = stream.readSByte();
98 		s->strengthExtMax = stream.readSByte();
99 		s->intelligenceCur = stream.readSByte();
100 		s->intelligenceMax = stream.readSByte();
101 		s->wisdomCur = stream.readSByte();
102 		s->wisdomMax = stream.readSByte();
103 		s->dexterityCur = stream.readSByte();
104 		s->dexterityMax = stream.readSByte();
105 		s->constitutionCur = stream.readSByte();
106 		s->constitutionMax = stream.readSByte();
107 		s->charismaCur = stream.readSByte();
108 		s->charismaMax = stream.readSByte();
109 		s->hitPointsCur = stream.readSint16BE();
110 		s->hitPointsMax = stream.readSint16BE();
111 		s->armorClass = stream.readSByte();
112 		s->disabledSlots = stream.readByte();
113 		s->raceSex = stream.readByte();
114 		s->cClass = stream.readByte();
115 		s->alignment = stream.readByte();
116 		s->portrait = stream.readSByte();
117 		s->food = stream.readByte();
118 		stream.read(s->level, 3);
119 		s->experience[0] = stream.readUint32BE();
120 		s->experience[1] = stream.readUint32BE();
121 		s->experience[2] = stream.readUint32BE();
122 		s->mageSpellsAvailableFlags = stream.readUint32BE();
123 		for (int ii = 0; ii < 27; ii++)
124 			s->inventory[ii] = stream.readSint16BE();
125 	}
126 
127 	ptr = e;
128 	return true;
129 }
130 
freeEoB2SeqData(void * & ptr,int & size)131 void StaticResource::freeEoB2SeqData(void *&ptr, int &size) {
132 	DarkMoonAnimCommand *d = (DarkMoonAnimCommand *)ptr;
133 	delete[] d;
134 	ptr = 0;
135 	size = 0;
136 }
137 
freeEoB2ShapeData(void * & ptr,int & size)138 void StaticResource::freeEoB2ShapeData(void *&ptr, int &size) {
139 	DarkMoonShapeDef *d = (DarkMoonShapeDef *)ptr;
140 	delete[] d;
141 	ptr = 0;
142 	size = 0;
143 }
144 
freeEoBNpcData(void * & ptr,int & size)145 void StaticResource::freeEoBNpcData(void *&ptr, int &size) {
146 	EoBCharacter *d = (EoBCharacter *)ptr;
147 	delete[] d;
148 	ptr = 0;
149 	size = 0;
150 }
151 
152 const ScreenDim Screen_EoB::_screenDimTable[] = {
153 	{ 0x00, 0x00, 0x28, 0xC8, 0x0F, 0x0C, 0x00, 0x00 },
154 	{ 0x08, 0x48, 0x18, 0x38, 0x0E, 0x0C, 0x00, 0x00 },
155 	{ 0x13, 0x40, 0x14, 0x80, 0x06, 0x0C, 0x00, 0x00 },
156 	{ 0x1D, 0x78, 0x08, 0x40, 0x0F, 0x0D, 0x00, 0x00 },
157 	{ 0x02, 0x18, 0x14, 0x78, 0x0F, 0x02, 0x03, 0x00 },
158 	{ 0x00, 0x00, 0x16, 0x78, 0x0F, 0x0D, 0x00, 0x00 },
159 	{ 0x0A, 0x6C, 0x15, 0x28, 0x0F, 0x00, 0x00, 0x00 },
160 	{ 0x01, 0xB4, 0x22, 0x12, 0x0F, 0x0C, 0x00, 0x00 },
161 	{ 0x02, 0x18, 0x14, 0x00, 0x0F, 0x02, 0x03, 0x00 },
162 	{ 0x01, 0x7D, 0x26, 0x40, 0x0F, 0x00, 0x03, 0x00 },
163 	{ 0x00, 0x00, 0x16, 0x90, 0x0F, 0x02, 0x00, 0x00 },
164 	{ 0x01, 0x14, 0x14, 0x38, 0x0F, 0x02, 0x00, 0x00 },
165 	{ 0x01, 0x04, 0x14, 0x9C, 0x0F, 0x02, 0x00, 0x00 },
166 	{ 0x01, 0x19, 0x26, 0x64, 0x0F, 0x02, 0x00, 0x00 },
167 	{ 0x01, 0x14, 0x14, 0x58, 0x0F, 0x02, 0x00, 0x00 },
168 	{ 0x02, 0x06, 0x23, 0x78, 0x0F, 0x02, 0x00, 0x00 },
169 	{ 0x09, 0x14, 0x16, 0x38, 0x0F, 0x02, 0x00, 0x00 },
170 	{ 0x01, 0x96, 0x26, 0x32, 0x0F, 0x00, 0x00, 0x00 },
171 	{ 0x01, 0x08, 0x26, 0x80, 0x0C, 0x0F, 0x00, 0x00 },
172 	{ 0x01, 0x10, 0x26, 0x14, 0x00, 0x0F, 0x06, 0x00 },
173 	{ 0x00, 0x10, 0x10, 0x0C, 0x00, 0x0F, 0x06, 0x00 },
174 	{ 0x00, 0x10, 0x17, 0x00, 0x00, 0x0F, 0x06, 0x00 },
175 	{ 0x00, 0x10, 0x10, 0x00, 0x00, 0x0F, 0x06, 0x00 },
176 	{ 0x00, 0x10, 0x07, 0x04, 0x00, 0x0F, 0x06, 0x00 },
177 	{ 0x00, 0x00, 0x11, 0x05, 0x00, 0x0F, 0x06, 0x00 },
178 	{ 0x00, 0x00, 0x15, 0x05, 0x00, 0x0F, 0x06, 0x00 },
179 	{ 0x00, 0x00, 0x11, 0x08, 0x00, 0x0F, 0x06, 0x00 },
180 	{ 0x00, 0x00, 0x15, 0x03, 0x00, 0x0F, 0x06, 0x00 },
181 	{ 0x0A, 0xA8, 0x15, 0x18, 0x0F, 0x0C, 0x00, 0x00 }
182 };
183 
184 const int Screen_EoB::_screenDimTableCount = ARRAYSIZE(Screen_EoB::_screenDimTable);
185 
186 const uint8 EoBCoreEngine::_hpIncrPerLevel[] = { 10, 4, 8, 6, 10, 10, 9, 10, 9, 10, 9, 9, 3, 1, 2, 2, 3, 3 };
187 
188 const uint8 EoBCoreEngine::_numLevelsPerClass[] = { 1, 1, 1, 1, 1, 1, 2, 2, 2, 3, 2, 2, 3, 2, 2 };
189 
190 const int8 EoBCoreEngine::_characterClassType[] = {
191 	0, -1, -1, 5, -1, -1, 4, -1, -1, 1, -1, -1, 2, -1, -1, 3, -1, -1,  0,
192 	2, -1, 0, 3, -1, 0, 1, -1, 0, 1, 3, 3, 1, -1, 2, 3, -1, 0, 2,  1,  5,
193 	2, -1, 2, 1, -1
194 };
195 
196 const int16 EoBCoreEngine::_hpConstModifiers[] = { -1, -3, -2, -2, -1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 6, 6, 7, 7 };
197 
198 const uint8 EoBCoreEngine::_charClassModifier[] = {
199 	0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x00, 0x00, 0x00, 0x00, 0x03, 0x02,
200 	0x00, 0x00, 0x02
201 };
202 
203 const uint8 EoBCoreEngine::_itemsOverlayCGA[] = {
204 	0x00, 0x55, 0x55, 0xFF
205 };
206 
207 const uint8 EoBCoreEngine::_teleporterShapeDefs[] = {
208 	0x0C, 0x58, 0x02, 0x0E,
209 	0x0C, 0x67, 0x01, 0x07,
210 	0x0C, 0x6F, 0x01, 0x07,
211 	0x0C, 0x77, 0x01, 0x05,
212 	0x0C, 0x7D, 0x01, 0x05,
213 	0x0C, 0x83, 0x01, 0x03
214 };
215 
216 const uint8 EoBCoreEngine::_wallOfForceShapeDefs[] = {
217 	0x00, 0x00, 0x04, 0x08,
218 	0x00, 0x08, 0x04, 0x08,
219 	0x04, 0x00, 0x04, 0x08,
220 	0x04, 0x08, 0x04, 0x08,
221 	0x08, 0x00, 0x05, 0x10,
222 	0x0C, 0x00, 0x05, 0x10
223 };
224 
225 const uint8 EoBCoreEngine::_buttonList1[] = {
226 	58, 0, 1, 2, 3, 90, 91, 4, 5, 6, 7, 8, 9, 10, 11, 12, 78, 79, 13, 14,  15,  16,
227 	80, 81, 17, 18, 19, 20, 82, 83, 49, 50, 51, 52, 53, 54, 56, 57, 255
228 };
229 
230 const uint8 EoBCoreEngine::_buttonList2[] = {
231 	58, 61, 62, 63, 64, 65, 93, 94, 66, 67, 68, 69, 70, 71, 76, 77, 88, 0, 1, 2, 3,
232 	90, 91,  4,  5, 6, 7, 8, 9, 10, 11, 12, 78, 79, 13, 14, 15, 16, 80, 81, 17, 18,
233 	19, 20, 82, 83, 49, 50, 51, 52, 53, 54, 56, 57, 255
234 };
235 
236 const uint8 EoBCoreEngine::_buttonList3[] = {
237 	58, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
238 	40, 41, 42, 43, 44, 45, 84, 85, 46, 47, 48, 60, 59, 92, 4, 5, 6, 7, 8, 49,  50,
239 	51, 52, 53, 54, 56, 57, 255
240 };
241 
242 const uint8 EoBCoreEngine::_buttonList4[] = {
243 	58, 47, 48, 60, 59, 92, 4, 5, 6, 7, 8, 49, 50, 51, 52, 53, 54, 56, 57, 255
244 };
245 
246 const uint8 EoBCoreEngine::_buttonList5[] = {
247 	58, 61, 62, 63, 64, 65, 93, 66, 67, 68, 69, 70, 71, 88, 21, 22, 23, 24, 25, 26,
248 	27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 84,
249 	85, 46, 47, 48, 60, 59, 92, 4, 5, 6, 7, 8, 49, 50, 51, 52, 53, 54, 56, 57, 255
250 };
251 
252 const uint8 EoBCoreEngine::_buttonList6[] = {
253 	58, 61, 62, 63, 64, 65, 93, 66, 67, 68, 69, 70, 71, 88, 46, 47, 48, 60, 59, 92,
254 	4, 5, 6, 7, 8, 49, 50, 51, 52, 53, 54, 56, 57, 255
255 };
256 
257 const uint8 EoBCoreEngine::_buttonList7[] = {
258 	17, 18, 19, 20, 82, 83, 55, 255
259 };
260 
261 const uint8 EoBCoreEngine::_buttonList8[] = {
262 	72, 73, 74, 75, 86, 87, 89, 255
263 };
264 
265 const uint8 EoBCoreEngine::_clock2Timers[] = {
266 	0x00, 0x01, 0x20, 0x21, 0x22, 0x22,
267 	0x30, 0x31, 0x32, 0x33, 0x34, 0x35,
268 	0x04, 0x05, 0x06, 0x07
269 };
270 
271 const uint8 EoBCoreEngine::_numClock2Timers = ARRAYSIZE(EoBCoreEngine::_clock2Timers);
272 
initStaticResource()273 void EoBCoreEngine::initStaticResource() {
274 	int temp, temp2;
275 	_chargenStatStrings = _staticres->loadStrings(kEoBBaseChargenStatStrings, temp);
276 	_chargenRaceSexStrings = _staticres->loadStrings(kEoBBaseChargenRaceSexStrings, temp);
277 	_chargenClassStrings = _staticres->loadStrings(kEoBBaseChargenClassStrings, temp);
278 	_chargenAlignmentStrings = _staticres->loadStrings(kEoBBaseChargenAlignmentStrings, temp);
279 
280 	_pryDoorStrings = _staticres->loadStrings(kEoBBasePryDoorStrings, temp);
281 	_warningStrings = _staticres->loadStrings(kEoBBaseWarningStrings, temp);
282 
283 	_suffixStringsRings = _staticres->loadStrings(kEoBBaseItemSuffixStringsRings, temp);
284 	_suffixStringsPotions = _staticres->loadStrings(kEoBBaseItemSuffixStringsPotions, temp);
285 	_suffixStringsWands = _staticres->loadStrings(kEoBBaseItemSuffixStringsWands, temp);
286 
287 	_ripItemStrings = _staticres->loadStrings(kEoBBaseRipItemStrings, temp);
288 	_cursedString = _staticres->loadStrings(kEoBBaseCursedString, temp);
289 	_enchantedString = _staticres->loadStrings(kEoBBaseEnchantedString, temp);
290 	_magicObjectStrings = _staticres->loadStrings(kEoBBaseMagicObjectStrings, temp);
291 	_magicObjectString5 = _staticres->loadStrings(kEoBBaseMagicObjectString5, temp);
292 	_patternSuffix = _staticres->loadStrings(kEoBBasePatternSuffix, temp);
293 	_patternGrFix1 = _staticres->loadStrings(kEoBBasePatternGrFix1, temp);
294 	_patternGrFix2 = _staticres->loadStrings(kEoBBasePatternGrFix2, temp);
295 	_validateArmorString = _staticres->loadStrings(kEoBBaseValidateArmorString, temp);
296 	_validateCursedString = _staticres->loadStrings(kEoBBaseValidateCursedString, temp);
297 	_validateNoDropString = _staticres->loadStrings(kEoBBaseValidateNoDropString, temp);
298 	_potionStrings = _staticres->loadStrings(kEoBBasePotionStrings, temp);
299 	_wandStrings = _staticres->loadStrings(kEoBBaseWandStrings, temp);
300 	_itemMisuseStrings = _staticres->loadStrings(kEoBBaseItemMisuseStrings, temp);
301 
302 	_takenStrings = _staticres->loadStrings(kEoBBaseTakenStrings, temp);
303 	_potionEffectStrings = _staticres->loadStrings(kEoBBasePotionEffectStrings, temp);
304 
305 	_yesNoStrings = _staticres->loadStrings(kEoBBaseYesNoStrings, temp);
306 	_npcMaxStrings = _staticres->loadStrings(kEoBBaseNpcMaxStrings, temp);
307 	_okStrings = _staticres->loadStrings(_flags.gameID == GI_EOB2 ? kEoBBaseOkStrings : kRpgCommonMoreStrings, temp);
308 	_npcJoinStrings = _staticres->loadStrings(kEoBBaseNpcJoinStrings, temp);
309 	_cancelStrings = _staticres->loadStrings(kEoBBaseCancelStrings, temp);
310 	_abortStrings = _staticres->loadStrings(_flags.gameID == GI_EOB2 ? kEoBBaseAbortStrings : kEoBBaseCancelStrings, temp);
311 
312 	_menuStringsMain = _staticres->loadStrings(kEoBBaseMenuStringsMain, temp);
313 	_menuStringsSaveLoad = _staticres->loadStrings(kEoBBaseMenuStringsSaveLoad, temp);
314 	_menuStringsOnOff = _staticres->loadStrings(kEoBBaseMenuStringsOnOff, temp);
315 	_menuStringsSpells = _staticres->loadStrings(kEoBBaseMenuStringsSpells, temp);
316 	_menuStringsRest = _staticres->loadStrings(kEoBBaseMenuStringsRest, temp);
317 	_menuStringsDrop = _staticres->loadStrings(kEoBBaseMenuStringsDrop, temp);
318 	_menuStringsExit = _staticres->loadStrings(kEoBBaseMenuStringsExit, temp);
319 	_menuStringsStarve = _staticres->loadStrings(kEoBBaseMenuStringsStarve, temp);
320 	_menuStringsScribe = _staticres->loadStrings(kEoBBaseMenuStringsScribe, temp);
321 	_menuStringsDrop2 = _staticres->loadStrings(kEoBBaseMenuStringsDrop2, temp);
322 	_menuStringsHead = _staticres->loadStrings(kEoBBaseMenuStringsHead, temp);
323 	_menuStringsPoison = _staticres->loadStrings(kEoBBaseMenuStringsPoison, temp);
324 	_menuStringsMgc = _staticres->loadStrings(kEoBBaseMenuStringsMgc, temp);
325 	_menuStringsPrefs = _staticres->loadStrings(kEoBBaseMenuStringsPrefs, temp);
326 	_menuStringsRest2 = _staticres->loadStrings(kEoBBaseMenuStringsRest2, temp);
327 	_menuStringsRest3 = _staticres->loadStrings(kEoBBaseMenuStringsRest3, temp);
328 	_menuStringsRest4 = _staticres->loadStrings(kEoBBaseMenuStringsRest4, temp);
329 	_menuStringsDefeat = _staticres->loadStrings(kEoBBaseMenuStringsDefeat, temp);
330 	_menuStringsTransfer = _staticres->loadStrings(kEoBBaseMenuStringsTransfer, temp);
331 	_menuStringsSpec = _staticres->loadStrings(kEoBBaseMenuStringsSpec, temp);
332 	_menuStringsSpellNo = _staticres->loadStrings(kEoBBaseMenuStringsSpellNo, temp);
333 	_menuYesNoStrings = _staticres->loadStrings(kEoBBaseMenuYesNoStrings, temp);
334 
335 	_spellLevelsMage = _staticres->loadRawData(kEoBBaseSpellLevelsMage, _spellLevelsMageSize);
336 	_spellLevelsCleric = _staticres->loadRawData(kEoBBaseSpellLevelsCleric, _spellLevelsClericSize);
337 	_numSpellsCleric = _staticres->loadRawData(kEoBBaseNumSpellsCleric, temp);
338 	_numSpellsWisAdj = _staticres->loadRawData(kEoBBaseNumSpellsWisAdj, temp);
339 	_numSpellsPal = _staticres->loadRawData(kEoBBaseNumSpellsPal, temp);
340 	_numSpellsMage = _staticres->loadRawData(kEoBBaseNumSpellsMage, temp);
341 
342 	_characterGuiStringsHp = _staticres->loadStrings(kEoBBaseCharGuiStringsHp, temp);
343 	_characterGuiStringsWp = _staticres->loadStrings(_flags.gameID == GI_EOB2 ? kEoBBaseCharGuiStringsWp2 : kEoBBaseCharGuiStringsWp1, temp);
344 	_characterGuiStringsWr = _staticres->loadStrings(kEoBBaseCharGuiStringsWr, temp);
345 	_characterGuiStringsSt = _staticres->loadStrings(_flags.gameID == GI_EOB2 ? kEoBBaseCharGuiStringsSt2 : kEoBBaseCharGuiStringsSt1, temp);
346 	_characterGuiStringsIn = _staticres->loadStrings(kEoBBaseCharGuiStringsIn, temp);
347 
348 	_characterStatusStrings7 = _staticres->loadStrings(kEoBBaseCharStatusStrings7, temp);
349 	_characterStatusStrings8 = _staticres->loadStrings(_flags.gameID == GI_EOB2 ? kEoBBaseCharStatusStrings82 : kEoBBaseCharStatusStrings81, temp);
350 	_characterStatusStrings9 = _staticres->loadStrings(kEoBBaseCharStatusStrings9, temp);
351 	_characterStatusStrings12 = _staticres->loadStrings(kEoBBaseCharStatusStrings12, temp);
352 	_characterStatusStrings13 = _staticres->loadStrings(_flags.gameID == GI_EOB2 ? kEoBBaseCharStatusStrings132 : kEoBBaseCharStatusStrings131, temp);
353 
354 	_textInputCharacterLines = _staticres->loadStrings(kEoBBaseTextInputCharacterLines, _textInputCharacterLinesSize);
355 	_textInputSelectStrings = _staticres->loadStrings(kEoBBaseTextInputSelectStrings, temp);
356 
357 	_levelGainStrings = _staticres->loadStrings(kEoBBaseLevelGainStrings, temp);
358 	for (int i = 0; i < 5; i++)
359 		_expRequirementTables[i] = _staticres->loadRawDataBe32(kEoBBaseExperienceTable0 + i, temp);
360 	_expRequirementTables[5] = _staticres->loadRawDataBe32(kEoBBaseExperienceTable4, temp);
361 
362 	_classModifierFlags = _staticres->loadRawData(kEoBBaseClassModifierFlags, temp);
363 
364 	_saveThrowTables[0] = _saveThrowTables[4] = _saveThrowTables[5] = _staticres->loadRawData(kEoBBaseSaveThrowTable1, temp);
365 	_saveThrowTables[1] = _staticres->loadRawData(kEoBBaseSaveThrowTable2, temp);
366 	_saveThrowTables[2] = _staticres->loadRawData(kEoBBaseSaveThrowTable3, temp);
367 	_saveThrowTables[3] = _staticres->loadRawData(kEoBBaseSaveThrowTable4, temp);
368 	_saveThrowLevelIndex = _staticres->loadRawData(kEoBBaseSaveThrwLvlIndex, temp);
369 	_saveThrowModDiv = _staticres->loadRawData(kEoBBaseSaveThrwModDiv, temp);
370 	_saveThrowModExt = _staticres->loadRawData(kEoBBaseSaveThrwModExt, temp);
371 
372 	_encodeMonsterShpTable = _staticres->loadRawDataBe16(kEoBBaseEncodeMonsterDefs, temp);
373 	_npcPreset = _staticres->loadEoBNpcData(kEoBBaseNpcPresets, temp);
374 	_npcPresetNames = _staticres->loadStrings(kEoBBaseNpcPresetsNames, temp);
375 
376 	_teleporterShapeCoords = _staticres->loadRawData(kEoBBaseDscTelptrShpCoords, temp);
377 	_portalSeq = (const int8 *)_staticres->loadRawData(kEoBBasePortalSeqData, temp);
378 	_mnDef = _staticres->loadRawData(kEoBBaseManDef, temp);
379 	_mnWord = _staticres->loadStrings(kEoBBaseManWord, _mnNumWord);
380 	_mnPrompt = _staticres->loadStrings(kEoBBaseManPrompt, temp);
381 
382 	_monsterStepTable0 = (const int8 *)_staticres->loadRawData(_flags.gameID == GI_EOB2 ? kEoBBaseMonsterStepTable02 : kEoBBaseMonsterStepTable01, temp);
383 	_monsterStepTable1 = (const int8 *)_staticres->loadRawData(kEoBBaseMonsterStepTable1, temp);
384 	_monsterStepTable2 = (const int8 *)_staticres->loadRawData(kEoBBaseMonsterStepTable2, temp);
385 	_monsterStepTable3 = (const int8 *)_staticres->loadRawData(kEoBBaseMonsterStepTable3, temp);
386 	_monsterCloseAttPosTable1 = _staticres->loadRawData(kEoBBaseMonsterCloseAttPosTable1, temp);
387 	_monsterCloseAttPosTable2 = _staticres->loadRawData(_flags.gameID == GI_EOB2 ? kEoBBaseMonsterCloseAttPosTable22 : kEoBBaseMonsterCloseAttPosTable21, temp);
388 	_monsterCloseAttUnkTable = (const int8 *)_staticres->loadRawData(kEoBBaseMonsterCloseAttUnkTable, temp);
389 	_monsterCloseAttChkTable1 = _staticres->loadRawData(kEoBBaseMonsterCloseAttChkTable1, temp);
390 	_monsterCloseAttChkTable2 = _staticres->loadRawData(kEoBBaseMonsterCloseAttChkTable2, temp);
391 	_monsterCloseAttDstTable1 = _staticres->loadRawData(kEoBBaseMonsterCloseAttDstTable1, temp);
392 	_monsterCloseAttDstTable2 = _staticres->loadRawData(kEoBBaseMonsterCloseAttDstTable2, temp);
393 
394 	_monsterProximityTable = _staticres->loadRawData(kEoBBaseMonsterProximityTable, temp);
395 	_findBlockMonstersTable = _staticres->loadRawData(kEoBBaseFindBlockMonstersTable, temp);
396 	_monsterDirChangeTable = (const int8 *)_staticres->loadRawData(kEoBBaseMonsterDirChangeTable, temp);
397 	_monsterSpecAttStrings = _staticres->loadStrings(kEoBBaseMonsterDistAttStrings, temp);
398 
399 	_monsterFrmOffsTable1 = (const int8 *)_staticres->loadRawData(kEoBBaseDscMonsterFrmOffsTbl1, temp);
400 	_monsterFrmOffsTable2 = (const int8 *)_staticres->loadRawData(kEoBBaseDscMonsterFrmOffsTbl2, temp);
401 
402 	_inventorySlotsX = _staticres->loadRawDataBe16(kEoBBaseInvSlotX, temp);
403 	_inventorySlotsY = _staticres->loadRawData(kEoBBaseInvSlotY, temp);
404 	_slotValidationFlags = _staticres->loadRawDataBe16(kEoBBaseSlotValidationFlags, temp);
405 
406 	_projectileWeaponAmmoTypes = (const int8 *)_staticres->loadRawData(kEoBBaseProjectileWeaponTypes, temp);
407 	_wandTypes = _staticres->loadRawData(kEoBBaseWandTypes, temp);
408 
409 	_drawObjPosIndex = _staticres->loadRawData(kEoBBaseDrawObjPosIndex, temp);
410 	_flightObjFlipIndex = _staticres->loadRawData(kEoBBaseFlightObjFlipIndex, temp);
411 	_flightObjShpMap = (const int8 *)_staticres->loadRawData(kEoBBaseFlightObjShpMap, temp);
412 	_flightObjSclIndex = (const int8 *)_staticres->loadRawData(kEoBBaseFlightObjSclIndex, temp);
413 
414 	_wllFlagPreset = _staticres->loadRawData(kEoBBaseWllFlagPreset, _wllFlagPresetSize);
415 	_dscShapeCoords = (const int16 *)_staticres->loadRawDataBe16(kEoBBaseDscShapeCoords, temp);
416 
417 	_dscDoorScaleMult1 = _staticres->loadRawData(kEoBBaseDscDoorScaleMult1, temp);
418 	_dscDoorScaleMult2 = _staticres->loadRawData(kEoBBaseDscDoorScaleMult2, temp);
419 	_dscDoorScaleMult3 = _staticres->loadRawData(kEoBBaseDscDoorScaleMult3, temp);
420 	_dscDoorY1 = _staticres->loadRawData(kEoBBaseDscDoorY1, temp);
421 	_dscDoorXE = _staticres->loadRawData(kEoBBaseDscDoorXE, temp);
422 
423 	_dscItemPosIndex = _staticres->loadRawData(kEoBBaseDscItemPosIndex, temp);
424 	_dscItemShpX = (const int16 *)_staticres->loadRawDataBe16(kEoBBaseDscItemShpX, temp);
425 	_dscItemScaleIndex = _staticres->loadRawData(kEoBBaseDscItemScaleIndex, temp);
426 	_dscItemTileIndex = _staticres->loadRawData(kEoBBaseDscItemTileIndex, temp);
427 	_dscItemShapeMap = _staticres->loadRawData(kEoBBaseDscItemShapeMap, temp);
428 
429 	_bookNumbers = _staticres->loadStrings(kEoBBaseBookNumbers, temp);
430 	_mageSpellList = _staticres->loadStrings(kEoBBaseMageSpellsList, _mageSpellListSize);
431 	_clericSpellList = _staticres->loadStrings(kEoBBaseClericSpellsList, temp);
432 	_mageSpellList2 = _staticres->loadStrings(_flags.platform == Common::kPlatformSegaCD ? kEoBBaseMageSpellsList2 : kEoBBaseMageSpellsList, temp);
433 	_clericSpellList2 = _staticres->loadStrings(_flags.platform == Common::kPlatformSegaCD ? kEoBBaseClericSpellsList2 : kEoBBaseClericSpellsList, temp);
434 	_spellNames = _staticres->loadStrings(kEoBBaseSpellNames, temp);
435 
436 	_magicStrings1 = _staticres->loadStrings(kEoBBaseMagicStrings1, temp);
437 	_magicStrings2 = _staticres->loadStrings(kEoBBaseMagicStrings2, temp);
438 	_magicStrings3 = _staticres->loadStrings(kEoBBaseMagicStrings3, temp);
439 	_magicStrings4 = _staticres->loadStrings(kEoBBaseMagicStrings4, temp);
440 	_magicStrings6 = _staticres->loadStrings(kEoBBaseMagicStrings6, temp);
441 	_magicStrings7 = _staticres->loadStrings(kEoBBaseMagicStrings7, temp);
442 	_magicStrings8 = _staticres->loadStrings(kEoBBaseMagicStrings8, temp);
443 	_magicStrings9 = _staticres->loadStrings(kEoBBaseMagicStrings9, temp);
444 
445 	_expObjectTlMode = _staticres->loadRawData(kEoBBaseExpObjectTlMode, temp);
446 	_expObjectTblIndex = _staticres->loadRawData(kEoBBaseExpObjectTblIndex, temp);
447 	_expObjectShpStart = _staticres->loadRawData(kEoBBaseExpObjectShpStart, temp);
448 	_expObjectAnimTbl1 = _staticres->loadRawData(kEoBBaseExpObjectTbl1, _expObjectAnimTbl1Size);
449 	_expObjectAnimTbl2 = _staticres->loadRawData(kEoBBaseExpObjectTbl2, _expObjectAnimTbl2Size);
450 	_expObjectAnimTbl3 = _staticres->loadRawData(kEoBBaseExpObjectTbl3, _expObjectAnimTbl3Size);
451 
452 	_sparkEffectDefSteps = _staticres->loadRawData(kEoBBaseSparkDefSteps, temp);
453 	_sparkEffectDefSubSteps = _staticres->loadRawData(kEoBBaseSparkDefSubSteps, temp);
454 	_sparkEffectDefShift = _staticres->loadRawData(kEoBBaseSparkDefShift, temp);
455 	_sparkEffectDefAdd = _staticres->loadRawData(kEoBBaseSparkDefAdd, temp);
456 	_sparkEffectDefX = _staticres->loadRawData(kEoBBaseSparkDefX, temp);
457 	_sparkEffectDefY = _staticres->loadRawData(kEoBBaseSparkDefY, temp);
458 	_sparkEffectOfFlags1 = _staticres->loadRawDataBe32(kEoBBaseSparkOfFlags1, temp);
459 	_sparkEffectOfFlags2 = _staticres->loadRawDataBe32(kEoBBaseSparkOfFlags2, temp);
460 	_sparkEffectOfShift = _staticres->loadRawData(kEoBBaseSparkOfShift, temp);
461 	_sparkEffectOfX = _staticres->loadRawData(kEoBBaseSparkOfX, temp);
462 	_sparkEffectOfY = _staticres->loadRawData(kEoBBaseSparkOfY, temp);
463 	_magicFlightObjectProperties = _staticres->loadRawData(kEoBBaseMagicFlightProps, temp);
464 	_turnUndeadEffect = _staticres->loadRawData(kEoBBaseTurnUndeadEffect, temp);
465 	_burningHandsDest = _staticres->loadRawData(kEoBBaseBurningHandsDest, temp);
466 	_coneOfColdDest1 = (const int8 *)_staticres->loadRawData(kEoBBaseConeOfColdDest1, temp);
467 	_coneOfColdDest2 = (const int8 *)_staticres->loadRawData(kEoBBaseConeOfColdDest2, temp);
468 	_coneOfColdDest3 = (const int8 *)_staticres->loadRawData(kEoBBaseConeOfColdDest3, temp);
469 	_coneOfColdDest4 = (const int8 *)_staticres->loadRawData(kEoBBaseConeOfColdDest4, temp);
470 	_coneOfColdGfxTbl = _staticres->loadRawData(kEoBBaseConeOfColdGfxTbl, _coneOfColdGfxTblSize);
471 
472 	_saveNamePatterns = _staticres->loadStrings(kEoBBaseSaveNamePatterns, temp);
473 
474 	if (_flags.platform == Common::kPlatformAmiga) {
475 		const char *const *map = _staticres->loadStrings(kEoBBaseSoundMap, temp2);
476 		_amigaSoundMap = new const char*[temp2];
477 		for (int i = 0; i < temp2; ++i) {
478 			assert(map[i]);
479 			_amigaSoundMap[i] = map[i][0] ? map[i] : 0;
480 		}
481 
482 		_amigaLevelSoundList1 = _staticres->loadStrings(kEoBBaseLevelSounds1, temp);
483 		_amigaLevelSoundList2 = _staticres->loadStrings(kEoBBaseLevelSounds2, temp);
484 
485 		const char *const *files = _staticres->loadStrings(kEoBBaseSoundFilesIngame, temp);
486 		SoundResourceInfo_AmigaEoB ingame(files, temp, _amigaSoundMap, temp2);
487 		files = _staticres->loadStrings(kEoBBaseSoundFilesIntro, temp);
488 		SoundResourceInfo_AmigaEoB intro(files, temp, 0, 0);
489 		files = _staticres->loadStrings(kEoBBaseSoundFilesFinale, temp);
490 		SoundResourceInfo_AmigaEoB finale(files, temp, 0, 0);
491 
492 		_sound->initAudioResourceInfo(kMusicIngame, &ingame);
493 		_sound->initAudioResourceInfo(kMusicIntro, &intro);
494 		_sound->initAudioResourceInfo(kMusicFinale, &finale);
495 
496 	} else if (_flags.platform == Common::kPlatformFMTowns) {
497 		const char *const *files = _staticres->loadStrings(kEoBBaseSoundFilesIngame, temp);
498 		const uint8 *data = _staticres->loadRawData(kEoB2PcmSoundEffectsIngame, temp2);
499 		SoundResourceInfo_TownsEoB ingame(files, temp, data, temp2, 127);
500 		files = _staticres->loadStrings(kEoBBaseSoundFilesIntro, temp);
501 		data = _staticres->loadRawData(kEoB2PcmSoundEffectsIntro, temp2);
502 		SoundResourceInfo_TownsEoB intro(files, temp, data, temp2, 40);
503 		files = _staticres->loadStrings(kEoBBaseSoundFilesFinale, temp);
504 		data = _staticres->loadRawData(kEoB2PcmSoundEffectsFinale, temp2);
505 		SoundResourceInfo_TownsEoB finale(files, temp, data, temp2, 40);
506 
507 		_sound->initAudioResourceInfo(kMusicIngame, &ingame);
508 		_sound->initAudioResourceInfo(kMusicIntro, &intro);
509 		_sound->initAudioResourceInfo(kMusicFinale, &finale);
510 
511 	} else if (_flags.platform != Common::kPlatformPC98) {
512 		const char *const *files = _staticres->loadStrings(kEoBBaseSoundFilesIngame, temp);
513 		SoundResourceInfo_PC ingame(files, temp);
514 		files = _staticres->loadStrings(kEoBBaseSoundFilesIntro, temp);
515 		SoundResourceInfo_PC intro(files, temp);
516 		files = _staticres->loadStrings(kEoBBaseSoundFilesFinale, temp);
517 		SoundResourceInfo_PC finale(files, temp);
518 
519 		_sound->initAudioResourceInfo(kMusicIngame, &ingame);
520 		_sound->initAudioResourceInfo(kMusicIntro, &intro);
521 		_sound->initAudioResourceInfo(kMusicFinale, &finale);
522 	}
523 
524 	// Hard code the following strings, since EOB I doesn't have them in the original.
525 	// EOB I doesn't have load and save menus, because there is only one single
526 	// save slot. Instead of emulating this we provide a menu similiar to EOB II.
527 	// EOB I SegaCD actually has save/load menus with more than 1 slot if there is
528 	// a RAM cart present). I supply the strings here, too...
529 
530 	static const char *const saveLoadStrings[8][4] = {
531 		{   "Cancel",   "Empty Slot",		"Save Game",    "Load Game"     },
532 		{   "Abbr.",    "Leerer Slot",		"Speichern",    "  Laden"       },
533 		{	" < < ",	"Posizione Vuota",	"Salva",		"Carica"	    },
534 		{	"Anular",	"Sin Uso",			"Grabar",		"Cargar"	    },
535 		{   0,          0,					0,					0			},
536 		{	0,          0,					0,					0			},
537 		{   "Cancel",   "\x82""d""\x82\x8d\x82\x90\x82\x94\x82\x99\x81""@""\x82\x92\x82\x85\x82\x87\x82\x89\x82\x8f\x82\x8e",		"Select save area",    "Select load data"     },
538 		{   "\x82\xe2\x82\xdf\x82\xe9",   "\x8b\xf3\x82\xab\x97\xcc\x88\xe6",	"\x82\xc7\x82\xb1\x82\xc9\x83""Z""\x81""|""\x83""u""\x82\xb5\x82\xdc\x82\xb7\x82\xa9\x81""H",	"\x82\xc7\x82\xea\x82\xf0\x83\x8d\x81""|""\x83""h""\x82\xb5\x82\xdc\x82\xb7\x82\xa9\x81""H"    }
539 	};
540 
541 	static const char *const errorSlotEmptyString[8] = {
542 		"There is no game\rsaved in that slot!",
543 		"Hier ist noch kein\rSpiel gespeichert!",
544 		"Non c'\x0E alcun gioco\rsalvato in quella\rposizione!",
545 		"No hay partidas\rgrabadas!",
546 		"\r ""\x82\xBB\x82\xCC\x83""X""\x83\x8D\x83""b""\x83""g""\x82\xC9\x82\xCD\x83""Q""\x81""[""\x83\x80\x82\xAA\x83""Z""\x81""[""\x83""u\r ""\x82\xB3\x82\xEA\x82\xC4\x82\xA2\x82\xDC\x82\xB9\x82\xF1\x81""B",
547 		"\x8b\xf3\x82\xab\x97\xcc\x88\xe6",
548 		0
549 	};
550 
551 	switch (_flags.lang) {
552 	case Common::EN_ANY: {
553 		if (_flags.platform == Common::kPlatformSegaCD) {
554 			_saveLoadStrings = saveLoadStrings[6];
555 			_errorSlotEmptyString = errorSlotEmptyString[5];
556 		} else {
557 			_saveLoadStrings = saveLoadStrings[0];
558 			_errorSlotEmptyString = errorSlotEmptyString[0];
559 		}
560 		break;
561 	}
562 	case Common::DE_DEU:
563 		_saveLoadStrings = saveLoadStrings[1];
564 		_errorSlotEmptyString = errorSlotEmptyString[1];
565 		break;
566 	case Common::IT_ITA:
567 		_saveLoadStrings = saveLoadStrings[2];
568 		_errorSlotEmptyString = errorSlotEmptyString[2];
569 		break;
570 	case Common::ES_ESP:
571 		_saveLoadStrings = saveLoadStrings[3];
572 		_errorSlotEmptyString = errorSlotEmptyString[3];
573 		break;
574 	case Common::JA_JPN:
575 		if (_flags.platform == Common::kPlatformSegaCD) {
576 			_saveLoadStrings = saveLoadStrings[7];
577 			_errorSlotEmptyString = errorSlotEmptyString[6];
578 		} else {
579 			// EOB II FM-Towns uses English here.
580 			// Only the empty slot warning is in Japanese.
581 			_saveLoadStrings = saveLoadStrings[0];
582 			_errorSlotEmptyString = errorSlotEmptyString[4];
583 		}
584 		break;
585 	default:
586 		_saveLoadStrings = saveLoadStrings[5];
587 		_errorSlotEmptyString = errorSlotEmptyString[7];
588 		break;
589 	}
590 
591 	_menuOkString = "OK";
592 }
593 
initButtonData()594 void EoBCoreEngine::initButtonData() {
595 	static const EoBGuiButtonDef buttonDefs[] = {
596 		{ 112, 0, 0x1100, 184, 2, 63, 50, 0 },
597 		{ 113, 0, 0x1100, 256, 2, 63, 50, 1 },
598 		{ 114, 0, 0x1100, 184, 54, 63, 50, 2 },
599 		{ 115, 0, 0x1100, 256, 54, 63, 50, 3 },
600 		{ 48, 110, 0x1100, 289, 177, 31, 21, 0 },
601 		{ 0, 0, 0x1100, 0, 102, 88, 18, 0 },
602 		{ 0, 0, 0x1100, 89, 102, 88, 18, 1 },
603 		{ 0, 0, 0x1100, 0, 72, 88, 29, 2 },
604 		{ 0, 0, 0x1100, 89, 72, 88, 29, 3 },
605 		{ 24, 0, 0x1100, 184, 10, 33, 33, 0 },
606 		{ 0, 0, 0x1100, 256, 10, 33, 33, 1 },
607 		{ 0, 0, 0x1100, 184, 62, 33, 33, 2 },
608 		{ 0, 0, 0x1100, 256, 62, 33, 33, 3 },
609 		{ 0, 0, 0x1100, 216, 10, 31, 33, 0 },
610 		{ 0, 0, 0x1100, 288, 10, 31, 33, 1 },
611 		{ 0, 0, 0x1100, 216, 62, 31, 33, 2 },
612 		{ 0, 0, 0x1100, 288, 62, 31, 33, 3 },
613 		{ 368, 0, 0x1000, 184, 2, 63, 8, 0 },
614 		{ 369, 0, 0x1000, 256, 2, 63, 8, 1 },
615 		{ 370, 0, 0x1000, 184, 54, 63, 8, 2 },
616 		{ 371, 0, 0x1000, 256, 54, 63, 8, 3 },
617 		{ 0, 0, 0x1100, 230, 116, 16, 16, 0 },
618 		{ 0, 0, 0x1100, 278, 116, 16, 16, 1 },
619 		{ 0, 0, 0x1100, 181, 40, 16, 16, 2 },
620 		{ 0, 0, 0x1100, 199, 40, 16, 16, 3 },
621 		{ 0, 0, 0x1100, 181, 58, 16, 16, 4 },
622 		{ 0, 0, 0x1100, 199, 58, 16, 16, 5 },
623 		{ 0, 0, 0x1100, 181, 76, 16, 16, 6 },
624 		{ 0, 0, 0x1100, 199, 76, 16, 16, 7 },
625 		{ 0, 0, 0x1100, 181, 94, 16, 16, 8 },
626 		{ 0, 0, 0x1100, 199, 94, 16, 16, 9 },
627 		{ 0, 0, 0x1100, 181, 112, 16, 16, 10 },
628 		{ 0, 0, 0x1100, 199, 112, 16, 16, 11 },
629 		{ 0, 0, 0x1100, 181, 130, 16, 16, 12 },
630 		{ 0, 0, 0x1100, 199, 130, 16, 16, 13 },
631 		{ 0, 0, 0x1100, 181, 148, 16, 16, 14 },
632 		{ 0, 0, 0x1100, 199, 148, 16, 16, 15 },
633 		{ 0, 0, 0x1100, 225, 55, 16, 16, 16 },
634 		{ 0, 0, 0x1100, 224, 76, 16, 16, 17 },
635 		{ 0, 0, 0x1100, 225, 96, 16, 16, 18 },
636 		{ 0, 0, 0x1100, 298, 55, 16, 16, 19 },
637 		{ 0, 0, 0x1100, 287, 75, 16, 16, 20 },
638 		{ 0, 0, 0x1100, 277, 137, 16, 16, 21 },
639 		{ 0, 0, 0x1100, 300, 94, 16, 16, 22 },
640 		{ 0, 0, 0x1100, 300, 112, 16, 16, 23 },
641 		{ 0, 0, 0x1100, 300, 130, 16, 16, 24 },
642 		{ 0, 0, 0x1100, 236, 37, 31, 16, 25 },
643 		{ 26, 0, 0x1100, 291, 149, 25, 17, 25 },
644 		{ 110, 24, 0x1100, 181, 3, 32, 32, 25 },
645 		{ 96, 352, 0x1100, 24, 128, 21, 16, 25 },
646 		{ 98, 97, 0x1100, 24, 144, 21, 16, 25 },
647 		{ 92, 348, 0x1100, 3, 144, 21, 16, 25 },
648 		{ 102, 358, 0x1100, 45, 144, 21, 16, 25 },
649 		{ 91, 0, 0x1100, 3, 128, 21, 16, 25 },
650 		{ 101, 0, 0x1100, 45, 128, 21, 16, 25 },
651 		{ 110, 0, 0x1100, 184, 0, 136, 120, 0 },
652 		{ 0, 0, 0x1100, 0, 8, 88, 48, 0 },
653 		{ 0, 0, 0x1100, 88, 8, 88, 48, 1 },
654 		{ 0, 0, 0x1100, 24, 8, 128, 96, 1 },
655 		{ 112, 113, 0x1100, 274, 35, 20, 15, 1 },
656 		{ 114, 115, 0x1100, 297, 35, 20, 15, 1 },
657 		{ 2, 0, 0x1100, 68, 121, 18, 10, 0 },
658 		{ 3, 0, 0x1100, 86, 121, 18, 10, 1 },
659 		{ 4, 0, 0x1100, 104, 121, 15, 10, 2 },
660 		{ 5, 0, 0x1100, 122, 121, 15, 10, 3 },
661 		{ 6, 0, 0x1100, 140, 121, 15, 10, 4 },
662 		{ 0, 0, 0x1100, 75, 131, 97, 6, 0 },
663 		{ 0, 0, 0x1100, 75, 137, 97, 6, 1 },
664 		{ 0, 0, 0x1100, 75, 143, 97, 6, 2 },
665 		{ 0, 0, 0x1100, 75, 149, 97, 6, 3 },
666 		{ 0, 0, 0x1100, 75, 155, 97, 6, 4 },
667 		{ 0, 0, 0x1100, 75, 161, 97, 6, 5 },
668 		{ 112, 0, 0x1100, 184, 2, 63, 50, 0 },
669 		{ 113, 0, 0x1100, 256, 2, 63, 50, 1 },
670 		{ 114, 0, 0x1100, 184, 54, 63, 50, 2 },
671 		{ 115, 0, 0x1100, 256, 54, 63, 50, 3 },
672 		{ 53, 54, 0x1100, 320, 200, 0, 0, 6 },
673 		{ 61, 0, 0x1100, 320, 200, 0, 0, 7 },
674 		{ 0, 0, 0x1100, 184, 114, 33, 33, 4 },
675 		{ 0, 0, 0x1100, 256, 114, 33, 33, 5 },
676 		{ 0, 0, 0x1100, 216, 114, 31, 33, 4 },
677 		{ 0, 0, 0x1100, 288, 114, 31, 33, 5 },
678 		{ 372, 0, 0x1000, 184, 106, 63, 8, 4 },
679 		{ 373, 0, 0x1000, 256, 106, 63, 8, 5 },
680 		{ 0, 0, 0x1100, 227, 135, 10, 10, 25 },
681 		{ 0, 0, 0x1100, 239, 135, 10, 10, 26 },
682 		{ 116, 0, 0x1100, 184, 106, 63, 50, 4 },
683 		{ 117, 0, 0x1100, 256, 106, 63, 50, 5 },
684 		{ 110, 0, 0x1100, 68, 168, 78, 10, 0 },
685 		{ 110, 0, 0x1100, 68, 168, 78, 10, 65535 },
686 		{ 116, 0, 0x1100, 184, 106, 63, 50, 4 },
687 		{ 117, 0, 0x1100, 256, 106, 63, 50, 5 },
688 		{ 116, 117, 0x1100, 320, 200, 1, 1, 2 },
689 		{ 7, 0, 0x1100, 158, 121, 15, 10, 5 },
690 		{ 0, 0, 0x1100, 146, 168, 32, 10, 0 },
691 		{ 0, 0, 0x1100, 296, 56, 16, 16, 27 },
692 
693 		{ 101, 96, 0x1100, 248, 152, 64, 14, 65535 },
694 		{ 103, 98, 0x1100, 248, 168, 64, 14, 1 },
695 		{ 110, 0, 0x1100, 248, 184, 64, 14, 2 }
696 	};
697 
698 	_buttonDefs = new EoBGuiButtonDef[ARRAYSIZE(buttonDefs)];
699 	memcpy(_buttonDefs, buttonDefs, sizeof(buttonDefs));
700 
701 	// The spellbook buttons in the table above are from EOB II. We make the necessary coordinates modifications for EOB I.
702 	if (_flags.gameID == GI_EOB1) {
703 		static const EoBGuiButtonDef eob1SpellbookButtonDefs[7] = {
704 			{ 2, 0, 0x1100, 71, 122, 20, 8, 0 },
705 			{ 3, 0, 0x1100, 92, 122, 20, 8, 1 },
706 			{ 4, 0, 0x1100, 113, 122, 20, 8, 2 },
707 			{ 5, 0, 0x1100, 134, 122, 20, 8, 3 },
708 			{ 6, 0, 0x1100, 155, 122, 20, 8, 4 },
709 			{ 110, 0, 0x1100, 75, 168, 97, 6, 0 },
710 			{ 110, 0, 0x1100, 160, 120, 16, 8, 0 }
711 		};
712 
713 		memcpy(&_buttonDefs[61], eob1SpellbookButtonDefs, 5 * sizeof(EoBGuiButtonDef));
714 		memcpy(&_buttonDefs[88], &eob1SpellbookButtonDefs[_flags.platform == Common::kPlatformSegaCD ? 6 : 5], sizeof(EoBGuiButtonDef));
715 		for (int i = 66; i < 72; ++i)
716 			_buttonDefs[i].y++;
717 		for (int i = 77; i < 79; ++i)
718 			_buttonDefs[i].y++;
719 
720 		if (_flags.platform == Common::kPlatformSegaCD) {
721 			for (int i = 0; i < 5; ++i) {
722 				_buttonDefs[61 + i].x = 80 + (i << 4);
723 				_buttonDefs[61 + i].y -= 2;
724 				_buttonDefs[61 + i].w -= 4;
725 			}
726 			for (int i = 0; i < 6; ++i) {
727 				_buttonDefs[66 + i].x = 80;
728 				_buttonDefs[66 + i].y = (16 + i) << 3;
729 				_buttonDefs[66 + i].w = 96;
730 				_buttonDefs[66 + i].h = 8;
731 			}
732 		}
733 	}
734 
735 	// Replace keycodes for EOB II FM-Towns
736 	if (_flags.platform == Common::kPlatformFMTowns) {
737 		static const uint16 keyCodesFMTowns[] = {
738 			93, 94, 95, 96, 67, 27, 24, 349, 350, 351, 352, 80, 27, 24, 30, 0, 31, 0, 29, 0, 28, 0, 127, 18, 27, 93, 94, 95, 96,
739 			49, 50, 51, 52, 53, 93, 94, 95, 96, 60, 62, 32, 353, 354, 97, 98, 27, 27, 97, 98, 97, 98, 54, 49, 50, 51, 52, 53, 27
740 		};
741 
742 		const uint16 *c = keyCodesFMTowns;
743 		for (int i = 0; i < ARRAYSIZE(buttonDefs); ++i) {
744 			if (_buttonDefs[i].keyCode)
745 				_buttonDefs[i].keyCode = *c++;
746 			if (_buttonDefs[i].keyCode2)
747 				_buttonDefs[i].keyCode2 = *c++;
748 		}
749 	}
750 
751 	// Adjust EOB I SegaCD button coordinates
752 	if (_flags.platform == Common::kPlatformSegaCD) {
753 		// Arrow field
754 		static const EoBGuiButtonDef eob1SegaArrowDefs[6] = {
755 			{ 96, 352, 0x1100, 29, 128, 21, 19, 25 },
756 			{ 98, 97, 0x1100, 29, 148, 21, 19, 25 },
757 			{ 92, 348, 0x1100, 8, 148, 21, 19, 25 },
758 			{ 102, 358, 0x1100, 50, 148, 21, 19, 25 },
759 			{ 91, 0, 0x1100, 8, 128, 21, 19, 25 },
760 			{ 101, 0, 0x1100, 50, 128, 21, 19, 25 }
761 		};
762 		memcpy(&_buttonDefs[49], eob1SegaArrowDefs, 6 * sizeof(EoBGuiButtonDef));
763 		// Character portrait boxes
764 		for (int i = 0; i < 4; ++i) {
765 			_buttonDefs[i].y = _buttonDefs[i + 17].y = _buttonDefs[i + 72].y = guiSettings()->charBoxCoords.boxY[i >> 1];
766 			_buttonDefs[i].h = _buttonDefs[i + 72].h = guiSettings()->charBoxCoords.boxHeight;
767 			_buttonDefs[i + 17].h = 16;
768 			_buttonDefs[9 + i].x = guiSettings()->charBoxCoords.facePosX_1[i & 1] + 176;
769 			_buttonDefs[9 + i].y = guiSettings()->charBoxCoords.facePosY_1[i >> 1];
770 			_buttonDefs[13 + i].y = guiSettings()->charBoxCoords.boxY[i >> 1] + 15;
771 		}
772 		for (int i = 4; i < 6; ++i) {
773 			_buttonDefs[i + 78].y = _buttonDefs[i + 82].y = _buttonDefs[i + 86].y = guiSettings()->charBoxCoords.boxY[i >> 1];
774 			_buttonDefs[i + 82].h = _buttonDefs[i + 86].h = guiSettings()->charBoxCoords.boxHeight;
775 			_buttonDefs[i + 78].h = 16;
776 			_buttonDefs[i + 74].x = guiSettings()->charBoxCoords.facePosX_1[i & 1] + 176;
777 			_buttonDefs[i + 74].y = guiSettings()->charBoxCoords.facePosY_1[i >> 1];
778 			_buttonDefs[i + 76].y = guiSettings()->charBoxCoords.boxY[i >> 1] + 15;
779 		}
780 		_buttonDefs[48].x = guiSettings()->charBoxCoords.facePosX_2[0];
781 		_buttonDefs[48].y = guiSettings()->charBoxCoords.facePosY_2[0];
782 	}
783 
784 	// Match the inventory button coords to the values that are used for drawing the inventory slots, so that
785 	// the buttons get fixed if the target uses a different inventory screen layout (currently only EOB I SegaCD).
786 	int temp = 0;
787 	const uint16 *invX = _staticres->loadRawDataBe16(kEoBBaseInvSlotX, temp);
788 	const uint8 *invY = _staticres->loadRawData(kEoBBaseInvSlotY, temp);
789 	for (int i = 0; i < 25; ++i) {
790 		_buttonDefs[21 + i].x = invX[i];
791 		_buttonDefs[21 + i].y = invY[i];
792 	}
793 	for (int i = 25; i < 27; ++i) {
794 		_buttonDefs[59 + i].x = invX[i];
795 		_buttonDefs[59 + i].y = invY[i];
796 	}
797 
798 	_buttonCallbacks.clear();
799 	_buttonCallbacks.reserve(ARRAYSIZE(buttonDefs));
800 
801 #define EOB_CBN(x, y) _buttonCallbacks.push_back(BUTTON_FUNCTOR(EoBCoreEngine, this, &EoBCoreEngine::y)); for (int l = 0; l < (x - 1); l++) { _buttonCallbacks.push_back(_buttonCallbacks[_buttonCallbacks.size() - 1 - l]); }
802 #define EOB_CBI(x, y) for (int l = x; l; l--) { _buttonCallbacks.push_back(_buttonCallbacks[y]); }
803 	EOB_CBN(4, clickedCharPortraitDefault);
804 	EOB_CBN(1, clickedCamp);
805 	EOB_CBN(4, clickedSceneDropPickupItem);
806 	EOB_CBN(4, clickedCharPortrait2);
807 	EOB_CBN(4, clickedWeaponSlot);
808 	EOB_CBN(4, clickedCharNameLabelRight);
809 	EOB_CBN(25, clickedInventorySlot);
810 	EOB_CBN(1, clickedEatItem);
811 	EOB_CBN(1, clickedInventoryNextPage);
812 	EOB_CBN(1, clickedPortraitRestore);
813 	EOB_CBN(1, clickedUpArrow);
814 	EOB_CBN(1, clickedDownArrow);
815 	EOB_CBN(1, clickedLeftArrow);
816 	EOB_CBN(1, clickedRightArrow);
817 	EOB_CBN(1, clickedTurnLeftArrow);
818 	EOB_CBN(1, clickedTurnRightArrow);
819 	EOB_CBN(1, clickedAbortCharSwitch);
820 	EOB_CBN(2, clickedSceneThrowItem);
821 	EOB_CBN(1, clickedSceneSpecial);
822 	EOB_CBN(1, clickedInventoryPrevChar);
823 	EOB_CBN(1, clickedInventoryNextChar);
824 	EOB_CBN(5, clickedSpellbookTab);
825 	EOB_CBN(6, clickedSpellbookList);
826 	EOB_CBN(4, clickedCastSpellOnCharacter);
827 	EOB_CBI(2, 66);
828 	EOB_CBI(2, 9);
829 	EOB_CBI(2, 13);
830 	EOB_CBI(2, 17);
831 	EOB_CBI(2, 21);
832 	EOB_CBI(2, 72);
833 	EOB_CBN(1, clickedSpellbookAbort);
834 	EOB_CBI(1, 72);
835 	EOB_CBI(2, 0);
836 	EOB_CBI(1, 60);
837 	EOB_CBI(1, 61);
838 	EOB_CBN(1, clickedSpellbookScroll);
839 	EOB_CBI(1, 21);
840 	EOB_CBN(3, clickedButtonReturnIndex);
841 #undef EOB_CBI
842 #undef EOB_CBN
843 }
844 
initMenus()845 void EoBCoreEngine::initMenus() {
846 	static const EoBMenuButtonDef buttonDefsDefault[] = {
847 		{  2,   12,  20, 158,  14,  20,  3  },
848 		{  3,   12,  37, 158,  14,  52,  3  },
849 		{  4,   12,  54, 158,  14,  26,  3  },
850 		{  5,   12,  71, 158,  14,  32,  3  },
851 		{  6,   12,  88, 158,  14,   0,  3  },
852 		{  7,   12, 105, 158,  14,  35,  3  },
853 		{  8,  128, 122,  40,  14,  19,  7  },
854 		{  9,   12,  20, 158,  14,  39,  3  },
855 		{  10,  12,  37, 158,  14,  32,  3  },
856 		{  11,  12,  54, 158,  14,  33,  3  },
857 		{  12,  12,  71, 158,  14,  17,  3  },
858 		{  8,  128, 122,  40,  14,  19,  7  },
859 		{  18,  12,  20, 158,  14,  32,  3  },
860 		{  19,  12,  37, 158,  14,  50,  3  },
861 		{  8,  128, 122,  40,  14,  19,  7  },
862 		{  8,  128, 122,  40,  14,  19,  5  },
863 		{  0,  184,   0,  64,  48, 112,  0  },
864 		{  0,  256,   0,  64,  48, 113,  0  },
865 		{  0,  184,  56,  64,  48, 114,  0  },
866 		{  0,  256,  56,  64,  48, 115,  0  },
867 		{  0,  184, 112,  64,  48, 116,  0  },
868 		{  0,  256, 112,  64,  48, 117,  0  },
869 		{  36,   8, 126,  48,  14,  48,  5  },
870 		{  8,  128, 126,  40,  14,  19,  5  },
871 		{  0,    0,  50, 168,  72,  61,  0  },
872 		{  31,  11,  16,  20,  18,   2,  5  },
873 		{  32,  38,  16,  20,  18,   3,  5  },
874 		{  33,  65,  16,  20,  18,   4,  5  },
875 		{  34,  92,  16,  20,  18,   5,  5  },
876 		{  35, 119,  16,  20,  18,   6,  5  },
877 		{  60, 146,  16,  20,  18,   7,  5  },
878 		{  61, 150,  16,  20,  18,   8,  5  },
879 		{  38,  16,  57,  32,  14,  22,  7  },
880 		{  39, 128,  57,  32,  14,  51,  7  },
881 		{  8,  128, 126,  40,  14,  19,  7  },
882 		{  0,    0,  50, 168,  72,  61,  0  },
883 		// EOB 1 memorize/pray menu:
884 		{  36,   8, 126,  48,  14,  48,  5  },
885 		{  8,  128, 126,  40,  14,  19,  5  },
886 		{  0,    0,  50, 168,  72,  61,  0  },
887 		{  31,   8,  16,  24,  20,   2,  5  },
888 		{  32,  40,  16,  24,  20,   3,  5  },
889 		{  33,  72,  16,  24,  20,   4,  5  },
890 		{  34, 104,  16,  24,  20,   5,  5  },
891 		{  35, 136,  16,  24,  20,   6,  5  },
892 		// FM-Towns options menu
893 		{  18,  12,  20, 158,  14,  32,  3  },
894 		{  19,  12,  37, 158,  14,  50,  3  },
895 		{  20,  12,  54, 158,  14,  21,  3  },
896 		{  8,  128, 122,  40,  14,  19,  7  },
897 		// PC-98 options menu
898 		{  17,  12,  20, 158,  14,  32,  3  },
899 		{  18,  12,  37, 158,  14,  50,  3  },
900 		{  19,  12,  54, 158,  14,  21,  3  },
901 		{  8,  128, 122,  40,  14,  19,  7  }
902 	};
903 
904 	static const EoBMenuButtonDef buttonDefsSegaCD[] = {
905 		{   0,   8,  40,  80,  16,  20,  3  },
906 		{   0,  88,  40,  80,  16,  52,  3  },
907 		{   0,  88,  64,  80,  16,  26,  3  },
908 		{   0,  88,  88,  80,  16,  32,  3  },
909 		{   0,   8, 112,  80,  16,   0,  3  },
910 		{   0,   0,   0,   0,   0,   0,  0  },
911 		{   0, 120, 144,  48,  16,  19,  7  },
912 		{   0,   8,  88,  80,  16,   0,  3  },
913 		{   0,   8,  64,  80,  16,   0,  3  },
914 		{   0,  88, 112,  80,  16,   0,  3  },
915 		{   0,   8, 112,  48,  16,   0,  3  },
916 		{   0, 120, 144,  48,  16,  19,  7  },
917 		{   0,   8,  64,  48,  16,   0,  3  },
918 		{   0,   8,  88,  48,  16,   0,  3  },
919 		{   0,   0,   0,   0,   0,   0,  0  },
920 		{   0,   8,  40,  48,  16,   0,  3  },
921 		{   0, 120,  40,  24,  16,   0,  3  },
922 		{   0,  24,  80,  48,  16,  48,  3  },
923 		{   0, 104,  80,  48,  16,  19,  3  },
924 		{   0, 120, 144,  48,  16,  19,  5  },
925 		{   0, 184,   2,  63,  50, 112,  0  },
926 		{   0, 256,   2,  63,  50, 113,  0  },
927 		{   0, 184,  58,  63,  50, 114,  0  },
928 		{   0, 256,  58,  63,  50, 115,  0  },
929 		{   0, 184, 114,  63,  50, 116,  0  },
930 		{   0, 256, 114,  63,  50, 117,  0  },
931 		{  36,   8, 144,  48,  16,  48,  5  },
932 		{  8,  120, 144,  48,  16,  19,  5  },
933 		{  0,    0,  50, 168,  72,  61,  0  },
934 		{  31,   8,  48,  24,  16,   2,  5  },
935 		{  32,  40,  48,  24,  16,   3,  5  },
936 		{  33,  72,  48,  24,  16,   4,  5  },
937 		{  34, 104,  48,  24,  16,   5,  5  },
938 		{  35, 136,  48,  24,  16,   6,  5  },
939 		{   0,  88, 112,  48,  16,   0,  3  },
940 		{   0, 120,  40,  24,  16,   0,  3  },
941 		{   0,   8,  40,  48,  16,   0,  3  },
942 		{   0,   8, 136,  80,  16,   0,  3  },
943 		{   0, 120, 144,  48,  16,   0,  3  },
944 		{   0,  24,  80,  80,  48,   0,  3  }
945 	};
946 
947 	_menuButtonDefs = (_flags.platform == Common::kPlatformSegaCD) ? buttonDefsSegaCD : buttonDefsDefault;
948 
949 	static const EoBMenuDef menuDefsDefault[7] = {
950 		{  1, 10,  0, 7,  9 },
951 		{  1, 10,  7, 5,  9 },
952 		{  1, 10, 12, 3,  9 },
953 		{  0, 10, 15, 7, 15 },
954 		{ 37, 10, 22, 9,  9 },
955 		{  0, 11, 32, 2, 15 },
956 		{ 48, 10, 34, 2,  9 }
957 	};
958 
959 	static const EoBMenuDef menuDefsSegaCD[7] = {
960 		{  -1, 0,  0, 10,   -1 },
961 		{  -1, 0,  0,  0,   -1 },
962 		{  -1, 0, 10,  7,   -1 },
963 		{   0, 0, 19,  7, 0x55 },
964 		{  -1, 0, 26,  8,   -1 },
965 		{  -1, 0, 17,  2,   -1 },
966 		{  -1, 0, 38,  2,   -1 }
967 	};
968 
969 	delete[] _menuDefs;
970 	if (_flags.platform == Common::kPlatformSegaCD) {
971 		_menuDefs = new EoBMenuDef[ARRAYSIZE(menuDefsSegaCD)];
972 		memcpy(_menuDefs, menuDefsSegaCD, sizeof(menuDefsSegaCD));
973 	} else {
974 		_menuDefs = new EoBMenuDef[ARRAYSIZE(menuDefsDefault)];
975 		memcpy(_menuDefs, menuDefsDefault, sizeof(menuDefsDefault));
976 		if (_flags.gameID == GI_EOB1) {
977 			// assign EOB 1 style memorize/pray menu
978 			_menuDefs[4].numButtons = 8;
979 			_menuDefs[4].firstButtonStrId = 36;
980 		}
981 
982 		if (_flags.platform == Common::kPlatformFMTowns) {
983 			// assign FM-Towns style options menu
984 			_menuDefs[2].numButtons = 4;
985 			_menuDefs[2].firstButtonStrId = 44;
986 			_prefMenuPlatformOffset = 32;
987 		} else if (_flags.platform == Common::kPlatformPC98) {
988 			// assign PC-98 style options menu
989 			_menuDefs[2].numButtons = 4;
990 			_menuDefs[2].firstButtonStrId = 48;
991 			_prefMenuPlatformOffset = 36;
992 		} else if (_flags.platform == Common::kPlatformAmiga) {
993 			// assign Amiga text colors
994 			_menuDefs[0].titleCol = _menuDefs[1].titleCol = _menuDefs[2].titleCol = _menuDefs[4].titleCol = _menuDefs[6].titleCol = guiSettings()->colors.guiColorLightBlue;
995 			_menuDefs[3].titleCol = _menuDefs[5].titleCol = guiSettings()->colors.guiColorWhite;
996 		}
997 	}
998 }
999 
1000 
initSpells()1001 void EoBCoreEngine::initSpells() {
1002 #define mpn magicTimingParaAssign.push_back(0);
1003 #define mp1n if (_flags.gameID == GI_EOB1) magicTimingParaAssign.push_back(0);
1004 #define mp2n if (_flags.gameID == GI_EOB2) magicTimingParaAssign.push_back(0);
1005 #define mp(x) magicTimingParaAssign.push_back(&magicTimingPara[x << 2]);
1006 #define mp1(x) if (_flags.gameID == GI_EOB1) magicTimingParaAssign.push_back(&magicTimingPara[x << 2]);
1007 #define mp2(x) if (_flags.gameID == GI_EOB2) magicTimingParaAssign.push_back(&magicTimingPara[x << 2]);
1008 
1009 #define sc(x) startCallback.push_back(&EoBCoreEngine::spellCallback_start_##x);
1010 #define sc1(x) if (_flags.gameID == GI_EOB1) startCallback.push_back(&EoBCoreEngine::spellCallback_start_##x);
1011 #define sc2(x) if (_flags.gameID == GI_EOB2) startCallback.push_back(&EoBCoreEngine::spellCallback_start_##x);
1012 #define ec(x) endCallback.push_back(&EoBCoreEngine::spellCallback_end_##x);
1013 #define ec1(x) if (_flags.gameID == GI_EOB1) endCallback.push_back(&EoBCoreEngine::spellCallback_end_##x);
1014 #define ec2(x) if (_flags.gameID == GI_EOB2) endCallback.push_back(&EoBCoreEngine::spellCallback_end_##x);
1015 
1016 	static const uint16 magicTimingPara[] = {
1017 		0, 546, 2, 1, // 0 detect magic
1018 		0, 546, 5, 1, // 1 shield, detect invis, magical vestment
1019 		0, 546, 1, 1, // 2 shocking grasp, vamp touch, true seeing, prayer
1020 		3, 546, 1, 1, // 3 blur, haste
1021 		5, 546, 1, 1, // 4 imp invisibility
1022 		6, 546, 0, 1, // 5 bless
1023 		0, 546, 3, 1, // 6 prot from evil
1024 		1, 546, 1, 1, // 7 aid
1025 		4, 546, 1, 1, // 8 flame blade
1026 		0, 32760, 1, 1, // 9 slow poison
1027 		1, 546, 0, 1, // 10 mystic defense
1028 	};
1029 
1030 	Common::Array<const uint16 *> magicTimingParaAssign;
1031 	mpn;
1032 	mpn;
1033 	mpn;
1034 	mp(0);  // Detect Magic
1035 	mpn;    // Magic Missile
1036 	mp1n;
1037 	mp(1);  // Shield
1038 	mp(2);  // Shocking Grasp
1039 	mp2(3); // Blur
1040 	mp2(1); // Detect Invis
1041 	mp2n;   // Imp Identify
1042 	mpn;    // Invis
1043 	mp1n;
1044 	mpn;    // Melf
1045 	mp1n;   // Stinking Cloud
1046 	mpn;    // Dispel Magic
1047 	mpn;    // Fireball
1048 	mp1n;   // Flame Arrow
1049 	mp(3);  // Haste
1050 	mpn;    // Hold Person
1051 	mpn;    // Invisibility
1052 	mpn;    // Lightning Bolt
1053 	mp(2);  // Vampiric Touch
1054 	mpn;    // Fear
1055 	mpn;    // Ice Storm
1056 	mp1n;   // Stone Skin
1057 	mp1n;   // Cloud Kill
1058 	mp2(4); // Improved Invisibility
1059 	mp2n;   // remove Curse
1060 	mpn;    // Cone of Cold
1061 	mpn;    // Hold Monster
1062 	mp2n;   // Wall of Force
1063 	mp2n;   // Disintegrate
1064 	mp2n;   // Flesh To Stone
1065 	mp2n;   // Stone To Flesh
1066 	mp2(2); // True Seeing
1067 	mp2n;   // Finger of Death
1068 	mp2n;   // Power Word Stun
1069 	mp2n;   // Bigby's Fist
1070 	mp2n;   // empty
1071 	mp(5);  // Bless
1072 	mpn;                        // EOB1: cure, EOB2: cause
1073 	mpn;                        // EOB1: cause, EOB2: cure
1074 	mp(0);  // Detect Magic
1075 	mp(6);  // Prot from Evil
1076 	mp(7);  // Aid
1077 	mp(8);  // Flame Blad
1078 	mpn;    // Hold Person
1079 	mp(9);  // Slow Poison
1080 	mpn;    // Create Food
1081 	mpn;    // Dispel Magic
1082 	mp(1);  // Magical Vestment
1083 	mp(2);  // Prayer
1084 	mpn;    // Remove Paralysis
1085 	mpn;                        // EOB1: cure, EOB2: cause
1086 	mpn;                        // EOB1: cause, EOB2: cure
1087 	mpn;    // Neutral Poison
1088 	mp(6);  // Prot From Evil 10'
1089 	mp1n;   // Prot From Lightning
1090 	mpn;                        // EOB1: cure, EOB2: cause
1091 	mpn;                        // EOB1: cause, EOB2: cure
1092 	mpn;    // Flame Strike
1093 	mpn;    // Raise Dead
1094 	mp2n;   // Slay Living
1095 	mp2(2); // True Seeing
1096 	mp2n;   // Harm
1097 	mp2n;   // Heal
1098 	mp2n;   // Resurrect
1099 	mpn;    // Lay on Hands
1100 	mp2n;   // Turn Undead
1101 	mpn;    // Lightning Bolt (EOB1) / Fireball 1(EOB2) passive
1102 	mp2(10);// Mystic Defense
1103 	mp2n;   // Fireball 2 passive
1104 	mpn;    // death spell passive
1105 	mpn;    // disintegrate passive
1106 	mp2n;   // cause critical passive
1107 	mp2n;   // flesh to stone passive
1108 
1109 	Common::Array<SpellStartCallback> startCallback;
1110 	sc(empty);
1111 	sc(armor);
1112 	sc(burningHands);
1113 	sc(detectMagic);
1114 	sc(magicMissile);
1115 	sc1(empty);
1116 	sc(empty);
1117 	sc(shockingGrasp);
1118 	sc(empty);
1119 	sc2(empty);
1120 	sc2(improvedIdentify);
1121 	sc(empty);
1122 	sc(melfsAcidArrow);
1123 	sc1(empty);     // Stinking Cloud
1124 	sc(dispelMagic);
1125 	sc(fireball);
1126 	sc1(flameArrow);
1127 	sc(empty);
1128 	sc(holdPerson);
1129 	sc(empty);
1130 	sc(lightningBolt);
1131 	sc(vampiricTouch);
1132 	sc(fear);
1133 	sc(iceStorm);
1134 	sc1(stoneSkin); // stone skin
1135 	sc2(empty); // imp invisibility
1136 	sc1(empty); // Cloudkill
1137 	sc2(removeCurse);
1138 	sc(coneOfCold);
1139 	sc(holdMonster);
1140 	sc2(wallOfForce);
1141 	sc2(disintegrate);
1142 	sc2(fleshToStone);
1143 	sc2(stoneToFlesh);
1144 	sc2(trueSeeing);
1145 	sc2(slayLiving);
1146 	sc2(powerWordStun);
1147 	sc2(empty);
1148 	sc2(empty);
1149 	sc(empty);  // Bless
1150 	sc2(causeLightWounds);
1151 	sc(cureLightWounds);
1152 	sc1(causeLightWounds);
1153 	sc(detectMagic);
1154 	sc(empty);
1155 	sc(aid);
1156 	sc(flameBlade);
1157 	sc(holdPerson);
1158 	sc(slowPoison);
1159 	sc(createFood);
1160 	sc(dispelMagic);
1161 	sc(empty);
1162 	sc(empty);
1163 	sc(removeParalysis);
1164 	sc2(causeSeriousWounds);
1165 	sc(cureSeriousWounds);
1166 	sc1(causeSeriousWounds);
1167 	sc(neutralizePoison);
1168 	sc(empty);
1169 	sc1(empty);
1170 	sc2(causeCriticalWounds);
1171 	sc(cureCriticalWounds);
1172 	sc1(causeCriticalWounds);
1173 	sc(flameStrike);
1174 	sc(raiseDead);
1175 	sc2(slayLiving);
1176 	sc2(trueSeeing);
1177 	sc2(harm);
1178 	sc2(heal);
1179 	sc2(empty);
1180 	sc(layOnHands);
1181 	sc2(turnUndead);
1182 	sc(empty);
1183 	sc2(empty);
1184 	sc2(empty);
1185 	sc(empty);
1186 	sc(empty);
1187 	sc2(empty);
1188 	sc2(empty);
1189 
1190 	Common::Array<SpellEndCallback> endCallback;
1191 	ec(empty);
1192 	ec(empty);
1193 	ec(empty);
1194 	ec(detectMagic);
1195 	ec(magicMissile);
1196 	ec1(empty);
1197 	ec(empty);
1198 	ec(shockingGraspFlameBlade);
1199 	ec(empty);
1200 	ec(empty);
1201 	ec2(empty);
1202 	ec2(empty);
1203 	ec(melfsAcidArrow);
1204 	ec1(empty);     // Stinking Cloud
1205 	ec(empty);
1206 	ec(fireball);
1207 	ec1(flameArrow);
1208 	ec(empty);
1209 	ec(holdPerson);
1210 	ec(empty);
1211 	ec(lightningBolt);
1212 	ec(vampiricTouch);
1213 	ec(empty);
1214 	ec(iceStorm);
1215 	ec(empty);      // EOB1: stone skin, EOB2: imp invisibility
1216 	ec(empty);      // EOB1: cloud kill, EOB2: remove curse
1217 	ec(empty);
1218 	ec(holdMonster);
1219 	ec2(empty);
1220 	ec2(empty);
1221 	ec2(empty);
1222 	ec2(empty);
1223 	ec2(trueSeeing);
1224 	ec2(empty);
1225 	ec2(empty);
1226 	ec2(empty);
1227 	ec2(empty);
1228 	ec(empty);  // Bless
1229 	ec(empty);
1230 	ec(empty);
1231 	ec(detectMagic);
1232 	ec(empty);
1233 	ec(aid);
1234 	ec(shockingGraspFlameBlade);
1235 	ec(holdPerson);
1236 	ec(slowPoison);
1237 	ec(empty);
1238 	ec(empty);
1239 	ec(empty);
1240 	ec(empty);
1241 	ec(empty);
1242 	ec(empty);
1243 	ec(empty);
1244 	ec(empty);
1245 	ec(empty);
1246 	ec1(empty); // Prot from Lightning
1247 	ec(empty);
1248 	ec(empty);
1249 	ec(flameStrike);
1250 	ec(empty);
1251 	ec2(empty);
1252 	ec2(trueSeeing);
1253 	ec2(empty);
1254 	ec2(empty);
1255 	ec2(empty);
1256 	ec(empty);
1257 	ec2(empty);
1258 	ec1(monster_lightningBolt);
1259 	ec2(monster_fireball1);
1260 	ec2(empty);
1261 	ec2(monster_fireball2);
1262 	ec(monster_deathSpell);
1263 	ec(monster_disintegrate);
1264 	ec2(monster_causeCriticalWounds);
1265 	ec2(monster_fleshToStone);
1266 
1267 	_spells = new EoBSpell[_numSpells];
1268 	memset(_spells, 0, _numSpells * sizeof(EoBSpell));
1269 
1270 	for (int i = 0, n = 0; i < _numSpells; i++, n++) {
1271 		EoBSpell *s = &_spells[i];
1272 
1273 		// Fix EoB 1 spell names
1274 		bool skip = false;
1275 		if (i == 5 || i == 9) {
1276 			n--;
1277 			skip = true;
1278 		}
1279 
1280 		s->name = _flags.gameID == GI_EOB2 ? ((i == 0 || i == _mageSpellListSize) ? _mageSpellList[0] : ((i < (_mageSpellListSize + 1)) ? _spellNames[i - 1] : _spellNames[i - 2])) : (skip ? _spellNames[0] : _spellNames[n]);
1281 		s->startCallback = startCallback[i];
1282 		s->timingPara = magicTimingParaAssign[i];
1283 		s->endCallback = endCallback[i];
1284 	}
1285 
1286 	magicTimingParaAssign.clear();
1287 	startCallback.clear();
1288 	endCallback.clear();
1289 
1290 	_clericSpellOffset = _mageSpellListSize;
1291 
1292 #undef mpn
1293 #undef mp1n
1294 #undef mp2n
1295 #undef mp
1296 #undef mp1
1297 #undef mp2
1298 #undef sc
1299 #undef sc1
1300 #undef sc2
1301 #undef ec
1302 #undef ec1
1303 #undef ec2
1304 }
1305 
initStaticResource()1306 void EoBEngine::initStaticResource() {
1307 	bool bigEndian = (_flags.platform == Common::kPlatformAmiga || _flags.platform == Common::kPlatformSegaCD);
1308 	int temp;
1309 	_mainMenuStrings = _staticres->loadStrings(kEoB1MainMenuStrings, temp);
1310 	_finBonusStrings = _staticres->loadStrings(kEoB1BonusStrings, temp);
1311 
1312 	_doorShapeEncodeDefs = _staticres->loadRawData(kEoB1DoorShapeDefs, temp);
1313 	_doorSwitchShapeEncodeDefs = _staticres->loadRawData(kEoB1DoorSwitchShapeDefs, temp);
1314 	_doorSwitchCoords = _staticres->loadRawData(kEoB1DoorSwitchCoords, temp);
1315 
1316 	_dscDoorScaleMult4 = _staticres->loadRawData(kEoBBaseDscDoorScaleMult4, temp);
1317 	_dscDoorScaleMult5 = _staticres->loadRawData(kEoBBaseDscDoorScaleMult5, temp);
1318 	_dscDoorScaleMult6 = _staticres->loadRawData(kEoBBaseDscDoorScaleMult6, temp);
1319 	_dscDoorY3 = _staticres->loadRawData(kEoBBaseDscDoorY3, temp);
1320 	_dscDoorY4 = _staticres->loadRawData(kEoBBaseDscDoorY4, temp);
1321 	_dscDoorY5 = _staticres->loadRawData(kEoBBaseDscDoorY5, temp);
1322 	_dscDoorY6 = _staticres->loadRawData(kEoBBaseDscDoorY6, temp);
1323 	_dscDoorY7 = _staticres->loadRawData(kEoBBaseDscDoorY7, temp);
1324 	_dscDoorCoordsExt = (const int16 *)_staticres->loadRawDataBe16(kEoBBaseDscDoorCoordsExt, temp);
1325 
1326 	_enemyMageSpellList = _staticres->loadRawData(kEoB1EnemyMageSpellList, temp);
1327 	_enemyMageSfx = _staticres->loadRawData(kEoB1EnemyMageSfx, temp);
1328 	_beholderSpellList = _staticres->loadRawData(kEoB1BeholderSpellList, temp);
1329 	_beholderSfx = _staticres->loadRawData(kEoB1BeholderSfx, temp);
1330 
1331 	_cgaMappingDefault = _staticres->loadRawData(kEoB1CgaMappingDefault, temp);
1332 	_cgaMappingAlt = _staticres->loadRawData(kEoB1CgaMappingAlt, temp);
1333 	_cgaMappingInv = _staticres->loadRawData(kEoB1CgaMappingInv, temp);
1334 	_cgaMappingItemsL = _staticres->loadRawData(kEoB1CgaMappingItemsL, temp);
1335 	_cgaMappingItemsS = _staticres->loadRawData(kEoB1CgaMappingItemsS, temp);
1336 	_cgaMappingThrown = _staticres->loadRawData(kEoB1CgaMappingThrown, temp);
1337 	_cgaMappingIcons = _staticres->loadRawData(kEoB1CgaMappingIcons, temp);
1338 	_cgaMappingDeco = _staticres->loadRawData(kEoB1CgaMappingDeco, temp);
1339 	_cgaLevelMappingIndex = _staticres->loadRawData(kEoB1CgaLevelMappingIndex, temp);
1340 	for (int i = 0; i < 5; i++)
1341 		_cgaMappingLevel[i] = _staticres->loadRawData(kEoB1CgaMappingLevel0 + i, temp);
1342 
1343 	_itemNamesStatic = _staticres->loadStrings(kEoB1ItemNames, _numItemNamesStatic);
1344 
1345 	_turnUndeadString = _staticres->loadStrings(kEoB1TurnUndeadString, temp);
1346 
1347 	_npcShpData = _staticres->loadRawData(kEoB1NpcShpData, temp);
1348 	_npcSubShpIndex1 = _staticres->loadRawData(kEoB1NpcSubShpIndex1, temp);
1349 	_npcSubShpIndex2 = _staticres->loadRawData(kEoB1NpcSubShpIndex2, temp);
1350 	_npcSubShpY = _staticres->loadRawData(kEoB1NpcSubShpY, temp);
1351 	for (int i = 0; i < 11; i++)
1352 		_npcStrings[i] = _staticres->loadStrings(kEoB1Npc0Strings + i, temp);
1353 
1354 	const uint8 *ps = _staticres->loadRawData(kEoB1MonsterProperties, temp);
1355 	temp /= 27;
1356 	_monsterProps = new EoBMonsterProperty[temp];
1357 	memset(_monsterProps, 0, temp * sizeof(EoBMonsterProperty));
1358 	// Convert EOB1 (hard coded) monster properties to EOB2 type monster properties.
1359 	for (int i = 0; i < temp; i++) {
1360 		EoBMonsterProperty *p = &_monsterProps[i];
1361 		p->armorClass = (int8)*ps++;
1362 		p->hitChance = (int8)*ps++;
1363 		p->level = (int8)*ps++;
1364 		p->attacksPerRound = *ps++;
1365 		p->dmgDc[0].times = *ps++;
1366 		p->dmgDc[0].pips = *ps++;
1367 		p->dmgDc[0].base = (int8)*ps++;
1368 		p->dmgDc[1].times = *ps++;
1369 		p->dmgDc[1].pips = *ps++;
1370 		p->dmgDc[1].base = (int8)*ps++;
1371 		p->dmgDc[2].times = *ps++;
1372 		p->dmgDc[2].pips = *ps++;
1373 		p->dmgDc[2].base = (int8)*ps++;
1374 		ps++;
1375 		p->capsFlags = *ps++;
1376 		p->typeFlags = bigEndian ? READ_BE_UINT32(++ps) : READ_LE_UINT32(ps);
1377 		ps += 4;
1378 		p->experience = bigEndian ? READ_BE_UINT16(ps) : READ_LE_UINT16(ps);
1379 		ps += 2;
1380 		p->u30 = *ps++;
1381 		p->sound1 = (int8)*ps++;
1382 		p->sound2 = (int8)*ps++;
1383 		p->numRemoteAttacks = *ps++;
1384 		p->tuResist = (int8)*ps++;
1385 		p->dmgModifierEvade = *ps++;
1386 	}
1387 
1388 	if (_flags.platform == Common::kPlatformPC98) {
1389 		const char *const *files = _staticres->loadStrings(kEoBBaseSoundFilesIngame, temp);
1390 		SoundResourceInfo_PC ingame(files, temp);
1391 		_sound->initAudioResourceInfo(kMusicIngame, &ingame);
1392 		files = _staticres->loadStrings(kEoBBaseSoundFilesIntro, temp);
1393 		SoundResourceInfo_PC intro(files, temp);
1394 		_sound->initAudioResourceInfo(kMusicIntro, &intro);
1395 		files = _staticres->loadStrings(kEoBBaseSoundFilesFinale, temp);
1396 		SoundResourceInfo_PC finale(files, temp);
1397 		_sound->initAudioResourceInfo(kMusicFinale, &finale);
1398 	}
1399 
1400 	_addrTbl1 = _staticres->loadRawDataBe16(kEoB1PatternAddTable1, temp);
1401 	_textFieldPattern = _staticres->loadRawDataBe16(kEoB1PatternAddTable2, temp);
1402 	_playFldPattern1 = _staticres->loadRawDataBe16(kEoB1PatternTable0, temp);
1403 	_invPattern = _staticres->loadRawDataBe16(kEoB1PatternTable3, temp);
1404 	_statsPattern = _staticres->loadRawDataBe16(kEoB1PatternTable4, temp);
1405 	_charTilesTable = _staticres->loadRawData(kEoB1CharTilesTable, temp);
1406 	_mapStrings1 = _staticres->loadStrings(kEoB1MapStrings1, temp);
1407 	_mapStrings2 = _staticres->loadStrings(kEoB1MapStrings2, temp);
1408 	_mapStrings3 = _staticres->loadStrings(kEoB1MapStrings3, temp);
1409 
1410 	// Build offset tables for door shapes encoding
1411 	if (_flags.platform == Common::kPlatformSegaCD) {
1412 		const uint8 *e1 = _doorShapeEncodeDefs;
1413 		const uint8 *e2 = _doorSwitchShapeEncodeDefs;
1414 		const uint8 **doorShapesSrc = new const uint8*[30];
1415 		const uint8 **doorSwitchShapesSrc = new const uint8*[15];
1416 
1417 		for (int i = 0; i < 5; ++i) {
1418 			const uint8 *shp = _screen->getCPagePtr(2);
1419 			for (int ii = 0; ii < 6; ++ii) {
1420 				doorShapesSrc[i * 6 + ii] = shp;
1421 				shp += ((e1[0] * e1[1]) << 5);
1422 				e1 += 4;
1423 			}
1424 			for (int ii = 0; ii < 3; ++ii) {
1425 				doorSwitchShapesSrc[i * 3 + ii] = shp;
1426 				shp += ((e2[0] * e2[1]) << 5);
1427 				e2 += 4;
1428 			}
1429 		}
1430 
1431 		_doorShapesSrc = doorShapesSrc;
1432 		_doorSwitchShapesSrc = doorSwitchShapesSrc;
1433 	}
1434 
1435 	_monsterAcHitChanceTable1 = _monsterAcHitChanceTbl1;
1436 	_monsterAcHitChanceTable2 = _monsterAcHitChanceTbl2;
1437 
1438 	static const char *const errorSlotNoNameString[5] = {
1439 		" You must specify\r a name for your\r save game!",
1440 		" Spielstaende mues-\r sen einen Namen\r haben!",
1441 		" Debes especificar\r un nombre para\r tu partida!",
1442 		"",
1443 		0
1444 	};
1445 
1446 	switch (_flags.lang) {
1447 	case Common::EN_ANY:
1448 		_errorSlotNoNameString = errorSlotNoNameString[0];
1449 		break;
1450 	case Common::DE_DEU:
1451 		_errorSlotNoNameString = errorSlotNoNameString[1];
1452 		break;
1453 	case Common::ES_ESP:
1454 		_errorSlotNoNameString = errorSlotNoNameString[2];
1455 		break;
1456 	case Common::JA_JPN:
1457 		_errorSlotNoNameString = errorSlotNoNameString[3];
1458 		break;
1459 	default:
1460 		_errorSlotNoNameString = errorSlotNoNameString[ARRAYSIZE(errorSlotNoNameString) - 1];
1461 	}
1462 }
1463 
initSpells()1464 void EoBEngine::initSpells() {
1465 	EoBCoreEngine::initSpells();
1466 
1467 	struct FlagTableEntry {
1468 		uint16 typeFlag;
1469 		uint32 effectFlag;
1470 		uint8 damageFlag;
1471 	};
1472 
1473 	static const FlagTableEntry flagTable[] = {
1474 		{ 0x0000, 0x000000, 0x00 }, // dummy
1475 		{ 0x0033, 0x000001, 0x00 }, // armor
1476 		{ 0x0100, 0x000000, 0x21 }, // burning hands
1477 		{ 0x004C, 0x000002, 0x00 }, // detect magic
1478 		{ 0x0100, 0x000000, 0x01 }, // magic missile
1479 		{ 0x0000, 0x000000, 0x00 }, // dummy
1480 		{ 0x008B, 0x000008, 0x00 }, // shield
1481 		{ 0x0488, 0x000000, 0x03 }, // shocking grasp
1482 		{ 0x0021, 0x000040, 0x00 }, // invisibility
1483 		{ 0x0000, 0x000000, 0x00 }, // dummy
1484 		{ 0x0100, 0x000000, 0x11 }, // melf's acid arrow
1485 		{ 0x0000, 0x000000, 0x00 }, // STINKING CLOUD
1486 		{ 0x00A0, 0x000000, 0x00 }, // dispel magic
1487 		{ 0x0100, 0x000000, 0x21 }, // fireball
1488 		{ 0x0100, 0x000000, 0x11 }, // FLAME ARROW
1489 		{ 0x0248, 0x010000, 0x00 }, // haste
1490 		{ 0x0100, 0x000000, 0x00 }, // hold person
1491 		{ 0x0240, 0x000040, 0x00 }, // inv 10'
1492 		{ 0x0100, 0x000000, 0x03 }, // lightning bolt
1493 		{ 0x0488, 0x000000, 0x01 }, // vampiric touch
1494 		{ 0x0100, 0x000000, 0x00 }, // fear
1495 		{ 0x0100, 0x000000, 0x41 }, // ice storm
1496 		{ 0x0033, 0x000001, 0x00 }, // STONE SKIN
1497 		{ 0x0000, 0x000000, 0x00 }, // CLOUD KILL
1498 		{ 0x0100, 0x000000, 0x41 }, // cone of cold
1499 		{ 0x0100, 0x000000, 0x00 }, // hold monster
1500 		{ 0x005C, 0x000400, 0x00 }, // bless
1501 		{ 0x0020, 0x000000, 0x00 }, // cure light wounds
1502 		{ 0x0100, 0x000000, 0x01 }, // cause light wounds
1503 		{ 0x004C, 0x000002, 0x00 }, // detect magic
1504 		{ 0x0029, 0x000800, 0x00 }, // prot from evil
1505 		{ 0x0039, 0x000000, 0x00 }, // aid
1506 		{ 0x2408, 0x000000, 0x21 }, // flame blade
1507 		{ 0x0100, 0x000000, 0x00 }, // hold person
1508 		{ 0x0028, 0x002000, 0x00 }, // slow poison
1509 		{ 0x0040, 0x000000, 0x00 }, // create food
1510 		{ 0x00A0, 0x000000, 0x00 }, // dispel magic
1511 		{ 0x0099, 0x004000, 0x00 }, // magical vestment
1512 		{ 0x004C, 0x008000, 0x00 }, // prayer
1513 		{ 0x0040, 0x000000, 0x00 }, // remove paralysis
1514 		{ 0x0020, 0x000000, 0x00 }, // cure serious
1515 		{ 0x0100, 0x000000, 0x01 }, // cause serious
1516 		{ 0x0020, 0x000000, 0x00 }, // neutralize poison
1517 		{ 0x0248, 0x000800, 0x00 }, // prot from evil 10'
1518 		{ 0x0000, 0x000000, 0x00 }, // PROT FROM LIGHTNING
1519 		{ 0x0020, 0x000000, 0x00 }, // cure critical
1520 		{ 0x0100, 0x000000, 0x01 }, // cause critical
1521 		{ 0x0100, 0x000000, 0x21 }, // flame strike
1522 		{ 0x0020, 0x000000, 0x00 }, // raise dead
1523 		{ 0x0020, 0x000000, 0x00 }, // lay on hands
1524 		{ 0x0000, 0x000000, 0x00 }, // obj hit passive
1525 		{ 0x0000, 0x000000, 0x00 }, // disintegrate passive
1526 		{ 0x0000, 0x000000, 0x00 }  // death spell passive
1527 	};
1528 
1529 	int temp;
1530 	const uint8 *src = _staticres->loadRawData(kEoBBaseSpellProperties, temp);
1531 	_clericSpellOffset -= 1;
1532 
1533 	for (int i = 0; i < _numSpells; i++) {
1534 		EoBSpell *s = &_spells[i];
1535 		if (_flags.platform == Common::kPlatformAmiga)
1536 			src++;
1537 		src += 4;
1538 		s->flags = flagTable[i].typeFlag;
1539 		s->damageFlags = flagTable[i].damageFlag;
1540 		s->effectFlags = flagTable[i].effectFlag;
1541 		s->sound = src[13];
1542 		src += 15;
1543 	}
1544 }
1545 
1546 const KyraRpgGUISettings EoBEngine::_guiSettingsVGA = {
1547 	{ _dlgButtonPosX_Def, _dlgButtonPosY_Def, 9, 15, 95, 9, 2, 7, { 285, 139 }, { 189, 162 }, { 31, 31 } },
1548 	{ 135, 130, 132, 180, 133, 17, 23, 20, 184, 177, 180, 184, 177, 180, 15, 6, 8, 9, 2, 5, 4, 3, 12 },
1549 	{	{ 184, 256, -1}, { 2, 54, 106 }, 64, 50,
1550 		{ 8, 80, -1 }, { 11, 63, 115 }, { 181, -1, -1 }, { 3, -1, -1 },
1551 		{ 40, 112, -1 }, { 11, 27, 63, 79, 115, 131 },
1552 		{ 23, 95, -1}, { 46, 98, 150 }, 38, 3, { 250, 250, -1}, { 16, 25, -1 }, 51, 5,
1553 		13, 30
1554 	}
1555 };
1556 
1557 const KyraRpgGUISettings EoBEngine::_guiSettingsEGA = {
1558 	{ _dlgButtonPosX_Def, _dlgButtonPosY_Def, 9, 15, 95, 9, 2, 7, { 285, 139 }, { 189, 162 }, { 31, 31 } },
1559 	{ 13, 9, 2, 14, 2, 6, 13, 8, 13, 15, 14, 13, 15, 14, 15, 6, 8, 9, 2, 5, 4, 3, 12 },
1560 	{	{ 184, 256, -1}, { 2, 54, 106 }, 64, 50,
1561 		{ 8, 80, -1 }, { 11, 63, 115 }, { 181, -1, -1 }, { 3, -1, -1 },
1562 		{ 40, 112, -1 }, { 11, 27, 63, 79, 115, 131 },
1563 		{ 23, 95, -1}, { 46, 98, 150 }, 38, 3, { 250, 250, -1}, { 16, 25, -1 }, 51, 5,
1564 		13, 30
1565 	}
1566 };
1567 
1568 const KyraRpgGUISettings EoBEngine::_guiSettingsPC98 = {
1569 	{ _dlgButtonPosX_Def, _dlgButtonPosY_Def, 9, 15, 95, 11, 1, 7, { 285, 139 }, { 189, 162 }, { 31, 31 } },
1570 	{ 13, 9, 2, 14, 2, 6, 13, 8, 13, 15, 14, 13, 15, 14, 15, 6, 8, 9, 2, 5, 4, 3, 12 },
1571 	{	{ 184, 256, -1}, { 2, 54, 106 }, 64, 50,
1572 		{ 8, 80, -1 }, { 11, 63, 115 }, { 181, -1, -1 }, { 3, -1, -1 },
1573 		{ 40, 112, -1 }, { 11, 27, 63, 79, 115, 131 },
1574 		{ 23, 95, -1}, { 46, 98, 150 }, 38, 3, { 250, 250, -1}, { 16, 25, -1 }, 51, 5,
1575 		13, 30
1576 	}
1577 };
1578 
1579 const KyraRpgGUISettings EoBEngine::_guiSettingsAmiga = {
1580 	{ _dlgButtonPosX_Def, _dlgButtonPosY_Def, 28, 31, 95, 9, 2, 7, { 285, 139 }, { 189, 162 }, { 31, 31 } },
1581 	{ 18, 17, 10, 17, 11, 24, 22, 25, 18, 9, 10, 18, 9, 10, 31, 24, 25, 28, 29, 7, 26, 27, 19 },
1582 	{	{ 184, 256, -1}, { 2, 54, 106 }, 64, 50,
1583 		{ 8, 80, -1 }, { 11, 63, 115 }, { 181, -1, -1 }, { 3, -1, -1 },
1584 		{ 40, 112, -1 }, { 11, 27, 63, 79, 115, 131 },
1585 		{ 23, 95, -1}, { 46, 98, 150 }, 38, 3, { 250, 250, -1}, { 16, 25, -1 }, 51, 5,
1586 		13, 30
1587 	}
1588 };
1589 
1590 const KyraRpgGUISettings EoBEngine::_guiSettingsAmigaMainMenu = {
1591 	{ _dlgButtonPosX_Def, _dlgButtonPosY_Def, 28, 31, 95, 9, 2, 7, { 285, 139 }, { 189, 162 }, { 31, 31 } },
1592 	{ 22, 28, 30, 17, 11, 24, 22, 25, 18, 9, 10, 18, 9, 10, 31, 24, 25, 28, 29, 7, 26, 27, 19 },
1593 	{	{ 184, 256, -1}, { 2, 54, 106 }, 64, 50,
1594 		{ 8, 80, -1 }, { 11, 63, 115 }, { 181, -1, -1 }, { 3, -1, -1 },
1595 		{ 40, 112, -1 }, { 11, 27, 63, 79, 115, 131 },
1596 		{ 23, 95, -1}, { 46, 98, 150 }, 38, 3, { 250, 250, -1}, { 16, 25, -1 }, 51, 5,
1597 		13, 30
1598 	}
1599 };
1600 
1601 const KyraRpgGUISettings EoBEngine::_guiSettingsSegaCD = {
1602 	{ _dlgButtonPosX_Sega, _dlgButtonPosY_Sega, 0x66, 0xFF, 90, 14, 2, 7, { 285, 139 }, { 189, 162 }, { 31, 31 } },
1603 	{ 135, 130, 132, 180, 0x00, 17, 23, 20, 184, 177, 180, 184, 177, 180, 15, 6, 0x31, 9, 2, 0x35, 4, 0x33, 0x3C },
1604 	{	{ 184, 256, -1}, { 1, 57, 113 }, 64, 55,
1605 		{ 8, 80, -1 }, { 16, 72, 128 }, { 184, -1, -1 }, { 8, -1, -1 },
1606 		{ 40, 112, -1 }, { 16, 32, 72, 88, 128, 144 },
1607 		{ 24, 96, -1}, { 51, 107, 163 }, 40, 2, { 248, 248, -1}, { 19, 27, -1 }, 47, 2,
1608 		16, 39
1609 	}
1610 
1611 };
1612 
1613 const uint8 EoBEngine::_redGridTile[8] = {
1614 	0x1C, 0x1C, 0x1C, 0x1C, 0xC1, 0xC1, 0xC1, 0xC1
1615 };
1616 
1617 const int8 EoBEngine::_sceneShakeOffsets[66] = {
1618 	0, 0, -1, -1, -1, 1, 1, 1, 1, -1, -1, -1, -1, 1, 1, 1, 1, -1, -2, -2, -2, 2, 2, 2, 2, -2, -2, -2, -2, 2, 2, 2, 2,
1619 	-2, -2, -2, -2, 2, 2, 2, 2, -2, -3, -3, -3, 3, 3, 3, 3, -3, -3, -3, -3, 3, 3, 3, 3, -3, -3, -3, -3, 3, 3, 3, 3, -3
1620 };
1621 
1622 const uint8 EoBEngine::_egaDefaultPalette[] = {
1623 	0, 5, 3, 2, 10, 14, 12, 6, 4, 11, 9, 1, 0, 8, 7, 15
1624 };
1625 
1626 const uint8 EoBEngine::_monsterAcHitChanceTbl1[] = {
1627 	3, 2, 1, 3
1628 };
1629 
1630 const uint8 EoBEngine::_monsterAcHitChanceTbl2[] = {
1631 	2, 1, 1, 1
1632 };
1633 
1634 const uint16 EoBEngine::_dlgButtonPosX_Sega[18] = { 59, 166, 4, 104, 204, 4, 104, 204, 4, 104, 204, 4, 104, 204, 4, 104, 204, 4 };
1635 
1636 const uint8 EoBEngine::_dlgButtonPosY_Sega[18] = { 16, 16, 16, 16, 16, 0, 0, 0, 16, 16, 16, 32, 32, 32, 16, 16, 16, 32 };
1637 
1638 const EoBEngine::RenderModePalFile EoBEngine::_renderModePalFiles[3] = {
1639 	{	Common::kRenderDefault, "EOBPAL.COL" },
1640 	{	Common::kRenderVGA, "EOBPAL.COL" },
1641 	{	-1, "" }
1642 };
1643 
1644 const EoBEngine::TitleScreenConfig EoBEngine::_titleConfig[5] = {
1645 	{
1646 		Common::kPlatformDOS,
1647 		Common::UNK_LANG,
1648 		"INTRO",
1649 		_renderModePalFiles,
1650 		-1,
1651 		2,
1652 		false,
1653 		77, 165, 173, 29, 14, 13, 12,
1654 		76, 164, 175, 31, 14, 13, -1,
1655 		0
1656 	},
1657 	{
1658 		Common::kPlatformAmiga,
1659 		Common::UNK_LANG,
1660 		"TITLE",
1661 		&_renderModePalFiles[2],
1662 		-1,
1663 		1,
1664 		true,
1665 		75, 165, 177, 29, 22, 28, -1,
1666 		74, 164, 179, 31, 22, 28, -1,
1667 		0
1668 	},
1669 	{
1670 		Common::kPlatformPC98,
1671 		Common::UNK_LANG,
1672 		"EOBTITLE",
1673 		&_renderModePalFiles[2],
1674 		1,
1675 		2,
1676 		false,
1677 		77, 161, 173, 29, 1, 2, 12,
1678 		76, 160, 175, 31, 1, 2, -1,
1679 		-8
1680 	},
1681 	{
1682 		Common::kPlatformDOS,
1683 		Common::ES_ESP,
1684 		"NNTRO",
1685 		_renderModePalFiles,
1686 		-1,
1687 		2,
1688 		false,
1689 		77, 165, 173, 29, 14, 13, 12,
1690 		76, 164, 175, 31, 14, 13, -1,
1691 		0
1692 	},
1693 	{
1694 		Common::kPlatformSegaCD,
1695 		Common::UNK_LANG,
1696 		"",
1697 		&_renderModePalFiles[2],
1698 		1,
1699 		2,
1700 		false,
1701 		77, 161, 173, 29, 1, 2, 12,
1702 		76, 160, 175, 31, 1, 2, -1,
1703 		41
1704 	}
1705 };
1706 
initStaticResource()1707 void DarkMoonEngine::initStaticResource() {
1708 	int temp;
1709 	_mainMenuStrings = _staticres->loadStrings(kEoB2MainMenuStrings, temp);
1710 
1711 	_dscDoorType5Offs = _staticres->loadRawData(kEoBBaseDscDoorType5Offs, temp);
1712 
1713 	_npcShpData = _staticres->loadRawData(kEoB2NpcShapeData, temp);
1714 	_npcStrings[0] = _staticres->loadStrings(kEoB2Npc1Strings, temp);
1715 	_npcStrings[1] = _staticres->loadStrings(kEoB2Npc2Strings, temp);
1716 	_monsterDustStrings = _staticres->loadStrings(kEoB2MonsterDustStrings, temp);
1717 	_dreamSteps = (const int8 *)_staticres->loadRawData(kEoB2DreamSteps, temp);
1718 	_kheldranStrings = _staticres->loadStrings(kEoB2KheldranStrings, temp);
1719 	_hornStrings = _staticres->loadStrings(kEoB2HornStrings, temp);
1720 	_hornSounds = _staticres->loadRawData(kEoB2HornSounds, temp);
1721 
1722 	_wallOfForceDsX = (const int16 *)_staticres->loadRawDataBe16(kEoB2WallOfForceDsX, temp);
1723 	_wallOfForceDsY = _staticres->loadRawData(kEoB2WallOfForceDsY, temp);
1724 	_wallOfForceDsNumW = _staticres->loadRawData(kEoB2WallOfForceNumW, temp);
1725 	_wallOfForceDsNumH = _staticres->loadRawData(kEoB2WallOfForceNumH, temp);
1726 	_wallOfForceShpId = _staticres->loadRawData(kEoB2WallOfForceShpId, temp);
1727 
1728 	_utilMenuStrings = _staticres->loadStrings(kEoB2UtilMenuStrings, temp);
1729 	_2431Strings = _staticres->loadStrings(kEoB2Config2431Strings, temp);
1730 
1731 	_ascii2SjisTables = _staticres->loadStrings(kEoB2Ascii2SjisTables, temp);
1732 	_ascii2SjisTables2 = _staticres->loadStrings(kEoB2Ascii2SjisTables2, temp);
1733 
1734 	_monsterAcHitChanceTable1 = _monsterAcHitChanceTbl1;
1735 	_monsterAcHitChanceTable2 = _monsterAcHitChanceTbl2;
1736 
1737 	_amigaSoundMapExtra = _staticres->loadStrings(kEoB2SoundMapExtra, temp);
1738 	_amigaSoundFiles2 = _staticres->loadStrings(kEoB2SoundFilesIngame2, temp);
1739 	_amigaSoundIndex1 = (const int8*)_staticres->loadRawData(kEoB2SoundIndex1, temp);
1740 	_amigaSoundIndex2 = _staticres->loadRawData(kEoB2SoundIndex2, temp);
1741 	_amigaSoundPatch = _staticres->loadRawData(kEoB2MonsterSoundPatchData, _amigaSoundPatchSize);
1742 
1743 	static const char *const errorSlotNoNameString[4] = {
1744 		" You must specify\r a name for your\r save game!",
1745 		" Spielst[nde m]ssen\r einen Namen haben!",
1746 		" Debes poner\run nombre al\rfichero!",
1747 		0
1748 	};
1749 
1750 	// ScummVM specific
1751 	static const char *const transferStringsScummVM[4][5] = {
1752 		{
1753 			"\r We cannot find any EOB save game\r file. Please make sure that the\r save game file with the party\r you wish to transfer is located\r in your ScummVM save game\r directory. If you have set up\r multiple save directories you\r have to copy the EOB save file\r into your EOB II save directory.\r Do you wish to try again?",
1754 			"Game ID",
1755 			"\r It seems that you have already\r defeated Xanathar here. Do you\r wish to transfer the party that\r finished the game? If not, you\r will be able to select a save\r game from the save game\r dialogue.",
1756 			"Select File",
1757 			"\r\r   Please wait..."
1758 		},
1759 		{
1760 			"\r Kein EOB-Spielstand zu finden.\r Bitte Spielstandsdatei mit der\r zu ]bernehmenden Gruppe in das\r ScummVM Spielstands-Verzeichnis\r kopieren. Bei mehreren Spiel-\r stands-Verzeichnissen bitte\r den EOB-Spielstand in das\r EOB II-Spielstands-Verzeichnis\r kopieren. Nochmal versuchen?",
1761 			"Game ID",
1762 			"\r Wie es scheint, wurde Xanathar\r hier bereits besiegt. Soll die\r Gruppe, mit der das Spiel be-\r endet wurde, ]bernommen werden?\r Falls nicht, kann ein Spielstand\r aus der Spielstandsliste gew[hlt\r werden.",
1763 			"Spiel W[hlen",
1764 			"\r\r  Bitte warten..."
1765 		},
1766 		{
1767 			"\r No se ha encontrado ninguna partida\r de EOB. Comprueba que el fichero de la partida que quieres\r transferir se encuentra en el\r directorio de ScummVM para los\r juegos guardados. Si tienes\r varios de estos directorios debes\r copiar el fichero en tu directorio\r de guardado de EOB II.\r Quieres volver a intentarlo?",
1768 			"Game ID",
1769 			"\r Parece que ya se ha vencido\r Xanathar aqui. Deseas transferir\r el grupo que ha finalizado el\r juego? En caso contrario puedes\r seleccionar otra partida de las\r anteriores guardadas.",
1770 			"Escoge Fichero",
1771 			"\r\r   Un momento\r   por favor..."
1772 		},
1773 		{
1774 			0, 0, 0, 0
1775 		}
1776 	};
1777 
1778 	switch(_flags.lang) {
1779 		case Common::EN_ANY:
1780 			_errorSlotNoNameString = errorSlotNoNameString[0];
1781 			_transferStringsScummVM = transferStringsScummVM[0];
1782 			break;
1783 		case Common::DE_DEU:
1784 			_errorSlotNoNameString = errorSlotNoNameString[1];
1785 			_transferStringsScummVM = transferStringsScummVM[1];
1786 			break;
1787 		case Common::ES_ESP:
1788 			_errorSlotNoNameString = errorSlotNoNameString[2];
1789 			_transferStringsScummVM = transferStringsScummVM[2];
1790 			break;
1791 		default:
1792 			_errorSlotNoNameString = errorSlotNoNameString[3];
1793 			_transferStringsScummVM = transferStringsScummVM[3];
1794 	}
1795 
1796 }
1797 
initSpells()1798 void DarkMoonEngine::initSpells() {
1799 	EoBCoreEngine::initSpells();
1800 
1801 	int temp;
1802 	const uint8 *data = _staticres->loadRawData(kEoBBaseSpellProperties, temp);
1803 	Common::MemoryReadStreamEndian src(data, temp, _flags.platform == Common::kPlatformAmiga);
1804 
1805 	for (int i = 0; i < _numSpells; i++) {
1806 		EoBSpell *s = &_spells[i];
1807 		src.skip(8);
1808 		s->flags = src.readUint16();
1809 		src.skip(8);
1810 		s->sound = src.readByte();
1811 		if (_flags.platform == Common::kPlatformAmiga)
1812 			src.skip(1);
1813 		s->effectFlags = src.readUint32();
1814 		s->damageFlags = src.readUint16();
1815 	}
1816 }
1817 
1818 const KyraRpgGUISettings DarkMoonEngine::_guiSettingsFMTowns = {
1819 	{ _dlgButtonPosX_Def, _dlgButtonPosY_Def, 9, 15, 95, 11, 1, 7, { 221, 76 }, { 187, 162 }, { 95, 95 } },
1820 	{ 186, 181, 183, 183, 184, 17, 23, 20, 186, 181, 183, 182, 177, 180, 15, 6, 8, 9, 2, 5, 4, 3, 12 },
1821 	{	{ 184, 256, -1}, { 2, 54, 106 }, 64, 50,
1822 		{ 8, 80, -1 }, { 11, 63, 115 }, { 181, -1, -1 }, { 3, -1, -1 },
1823 		{ 40, 112, -1 }, { 11, 27, 63, 79, 115, 131 },
1824 		{ 23, 95, -1}, { 46, 98, 150 }, 38, 3, { 250, 250, -1}, { 16, 25, -1 }, 51, 5,
1825 		13, 30
1826 	}
1827 };
1828 
1829 const KyraRpgGUISettings DarkMoonEngine::_guiSettingsDOS = {
1830 	{ _dlgButtonPosX_Def, _dlgButtonPosY_Def, 9, 15, 95, 9, 2, 7, { 221, 76 }, { 189, 162 }, { 95, 95 } },
1831 	{ 186, 181, 183, 183, 184, 17, 23, 20, 186, 181, 183, 182, 177, 180, 15, 6, 8, 9, 2, 5, 4, 3, 12 },
1832 	{	{ 184, 256, -1}, { 2, 54, 106 }, 64, 50,
1833 		{ 8, 80, -1 }, { 11, 63, 115 }, { 181, -1, -1 }, { 3, -1, -1 },
1834 		{ 40, 112, -1 }, { 11, 27, 63, 79, 115, 131 },
1835 		{ 23, 95, -1}, { 46, 98, 150 }, 38, 3, { 250, 250, -1}, { 16, 25, -1 }, 51, 5,
1836 		13, 30
1837 	}
1838 };
1839 
1840 const KyraRpgGUISettings DarkMoonEngine::_guiSettingsAmiga = {
1841 	{ _dlgButtonPosX_Def, _dlgButtonPosY_Def, 28, 31, 95, 9, 2, 7, { 221, 76 }, { 189, 162 }, { 95, 95 } },
1842 	{ 18, 17, 10, 17, 11, 10, 12, 25, 18, 9, 10, 18, 9, 10, 31, 24, 25, 28, 29, 7, 26, 27, 19 },
1843 	{	{ 184, 256, -1}, { 2, 54, 106 }, 64, 50,
1844 		{ 8, 80, -1 }, { 11, 63, 115 }, { 181, -1, -1 }, { 3, -1, -1 },
1845 		{ 40, 112, -1 }, { 11, 27, 63, 79, 115, 131 },
1846 		{ 23, 95, -1}, { 46, 98, 150 }, 38, 3, { 250, 250, -1}, { 16, 25, -1 }, 51, 5,
1847 		13, 30
1848 	}
1849 };
1850 
1851 const uint8 DarkMoonEngine::_egaDefaultPalette[] = {
1852 	0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
1853 };
1854 
1855 const uint8 DarkMoonEngine::_monsterAcHitChanceTbl1[] = {
1856 	1, 3, 3, 2
1857 };
1858 
1859 const uint8 DarkMoonEngine::_monsterAcHitChanceTbl2[] = {
1860 	1, 1, 2, 1
1861 };
1862 
1863 #endif // ENABLE_EOB
1864 
1865 } // End of namespace Kyra
1866