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 #ifdef ENABLE_EOB
24
25 #include "kyra/engine/eobcommon.h"
26 #include "kyra/script/script_eob.h"
27 #include "kyra/resource/resource.h"
28 #include "kyra/engine/timer.h"
29
30 #include "common/system.h"
31
32
33 namespace Kyra {
34
loadMonsterShapes(const char * filename,int monsterIndex,bool hasDecorations,int encodeTableIndex)35 void EoBCoreEngine::loadMonsterShapes(const char *filename, int monsterIndex, bool hasDecorations, int encodeTableIndex) {
36 _screen->loadShapeSetBitmap(filename, 3, 3);
37 const uint16 *enc = &_encodeMonsterShpTable[encodeTableIndex << 2];
38
39 for (int i = 0; i < 6; i++, enc += 4)
40 _monsterShapes[monsterIndex + i] = _screen->encodeShape(enc[0], enc[1], enc[2], enc[3], false, _cgaMappingDefault);
41
42 generateMonsterPalettes(filename, monsterIndex);
43
44 if (hasDecorations) {
45 Common::SeekableReadStream *s = _res->createReadStream(Common::String::format("%s.DCR", filename));
46 if (s)
47 loadMonsterDecoration(s, monsterIndex);
48 delete s;
49 }
50
51 _screen->_curPage = 0;
52 }
53
releaseMonsterShapes(int first,int num)54 void EoBCoreEngine::releaseMonsterShapes(int first, int num) {
55 for (int i = first; i < first + num; i++) {
56 delete[] _monsterShapes[i];
57 _monsterShapes[i] = 0;
58 delete[] _monsterDecorations[i].shp;
59 _monsterDecorations[i].shp = 0;
60 }
61 }
62
loadActiveMonsterData(const uint8 * data,int level)63 const uint8 *EoBCoreEngine::loadActiveMonsterData(const uint8 *data, int level) {
64 static const uint8 intervals[4] = { 35, 30, 25, 0 };
65 for (uint8 p = *data++; p != 0xFF; p = *data++) {
66 uint8 v = *data++;
67 if (_flags.platform == Common::kPlatformSegaCD) {
68 assert(v < ARRAYSIZE(intervals));
69 v = intervals[v];
70 }
71 _timer->setCountdown(0x20 + (p << 1), v);
72 _timer->setCountdown(0x21 + (p << 1), v);
73 }
74
75 uint32 ct = _system->getMillis();
76 for (int i = 0x20; i < 0x24; i++) {
77 int32 del = _timer->getDelay(i);
78 _timer->setNextRun(i, (i & 1) ? ct + (del >> 1) * _tickLength : ct + del * _tickLength);
79 }
80 _timer->resetNextRun();
81
82 if (_hasTempDataFlags & (1 << (level - 1)))
83 return data + 420;
84
85 memset(_monsters, 0, 30 * sizeof(EoBMonsterInPlay));
86
87 for (int i = 0; i < 30; i++, data += 14) {
88 if (*data == 0xFF)
89 continue;
90
91 initMonster(data[0], data[1], READ_LE_UINT16(&data[2]), data[4], (int8)data[5], data[6], data[7], data[8], data[9], READ_LE_UINT16(&data[10]), READ_LE_UINT16(&data[12]));
92 _monsters[data[0]].flags |= 0x40;
93 }
94
95 return data;
96 }
97
initMonster(int index,int unit,uint16 block,int pos,int dir,int type,int shpIndex,int mode,int i,int randItem,int fixedItem)98 void EoBCoreEngine::initMonster(int index, int unit, uint16 block, int pos, int dir, int type, int shpIndex, int mode, int i, int randItem, int fixedItem) {
99 EoBMonsterInPlay *m = &_monsters[index];
100 EoBMonsterProperty *p = &_monsterProps[type];
101 memset(m, 0, sizeof(EoBMonsterInPlay));
102
103 if (!block)
104 return;
105
106 unit <<= 1;
107 if (index & 1)
108 unit++;
109
110 m->stepsTillRemoteAttack = _flags.gameID == GI_EOB2 ? rollDice(1, 3, 0) : 5;
111 m->type = type;
112 m->numRemoteAttacks = p->numRemoteAttacks;
113 m->curRemoteWeapon = 0;
114 m->unit = unit;
115 m->pos = pos;
116 m->shpIndex = shpIndex;
117 m->mode = mode;
118 m->spellStatusLeft = i;
119 m->dir = dir;
120 m->palette = _flags.gameID == GI_EOB2 ? (index % 3) : 0;
121 m->hitPointsCur = m->hitPointsMax = _flags.gameID == GI_EOB2 ? rollDice(p->hpDcTimes, p->hpDcPips, p->hpDcBase) : (p->level == -1 ? rollDice(1, 4, 0) : rollDice(p->level, 8, 0));
122 m->randItem = randItem;
123 m->fixedItem = fixedItem;
124 m->sub = _currentSub;
125
126 placeMonster(m, block, dir);
127 }
128
placeMonster(EoBMonsterInPlay * m,uint16 block,int dir)129 void EoBCoreEngine::placeMonster(EoBMonsterInPlay *m, uint16 block, int dir) {
130 if (block != 0xFFFF) {
131 checkSceneUpdateNeed(m->block);
132 if (_levelBlockProperties[m->block].flags & 7) {
133 _levelBlockProperties[m->block].flags--;
134 if (_flags.gameID == GI_EOB2)
135 runLevelScript(m->block, 0x400);
136 }
137 m->block = block;
138 _levelBlockProperties[block].flags++;
139 if (_flags.gameID == GI_EOB2)
140 runLevelScript(m->block, 0x200);
141 }
142
143 if (dir != -1) {
144 m->dir = dir;
145 block = m->block;
146 }
147
148 checkSceneUpdateNeed(block);
149 }
150
killMonster(EoBMonsterInPlay * m,bool giveExperience)151 void EoBCoreEngine::killMonster(EoBMonsterInPlay *m, bool giveExperience) {
152 m->hitPointsCur = -1;
153 int pos = (m->pos == 4) ? rollDice(1, 4, -1) : m->pos;
154
155 if (m->randItem) {
156 if (rollDice(1, _flags.gameID == GI_EOB1 ? 2 : 10, 0) == 1)
157 setItemPosition((Item *)&_levelBlockProperties[m->block & 0x3FF].drawObjects, m->block, duplicateItem(m->randItem), pos);
158 }
159
160 if (m->fixedItem)
161 setItemPosition((Item *)&_levelBlockProperties[m->block & 0x3FF].drawObjects, m->block, duplicateItem(m->fixedItem), pos);
162
163 if (giveExperience)
164 increasePartyExperience(_monsterProps[m->type].experience);
165
166 if (_totalEnemiesKilled < 0xFFFF)
167 _totalEnemiesKilled++;
168
169 if (killMonsterExtra(m)) {
170 placeMonster(m, 0, -1);
171
172 if (m->mode == 8)
173 updateAttackingMonsterFlags();
174 }
175 }
176
countSpecificMonsters(int type)177 int EoBCoreEngine::countSpecificMonsters(int type) {
178 int res = 0;
179 for (int i = 0; i < 30; i++) {
180 if (_monsters[i].type != type || _monsters[i].sub != _currentSub || _monsters[i].hitPointsCur < 0)
181 continue;
182 res++;
183 }
184 return res;
185 }
186
updateAttackingMonsterFlags()187 void EoBCoreEngine::updateAttackingMonsterFlags() {
188 EoBMonsterInPlay *m2 = 0;
189 for (EoBMonsterInPlay *m = _monsters; m < &_monsters[30]; m++) {
190 if (m->mode != 8)
191 continue;
192 m->mode = 0;
193 m->dest = _currentBlock;
194 m2 = m;
195 }
196
197 if (!m2)
198 return;
199
200 if (m2->type == 7)
201 setScriptFlags(4);
202
203 if (m2->type == 12)
204 setScriptFlags(0x800);
205 }
206
getMonstersOnBlockPositions(uint16 block)207 const int8 *EoBCoreEngine::getMonstersOnBlockPositions(uint16 block) {
208 memset(_monsterBlockPosArray, -1, sizeof(_monsterBlockPosArray));
209 for (int8 i = 0; i < 30; i++) {
210 if (_monsters[i].block != block)
211 continue;
212 assert(_monsters[i].pos < sizeof(_monsterBlockPosArray));
213 _monsterBlockPosArray[_monsters[i].pos] = i;
214 }
215 return _monsterBlockPosArray;
216 }
217
getClosestMonster(int charIndex,int block)218 int EoBCoreEngine::getClosestMonster(int charIndex, int block) {
219 const int8 *pos = getMonstersOnBlockPositions(block);
220 if (pos[4] != -1)
221 return pos[4];
222
223 const uint8 *p = &_monsterProximityTable[(_currentDirection << 3) + ((charIndex & 1) << 2)];
224 for (int i = 0; i < 4; i++) {
225 if (pos[p[i]] != -1)
226 return pos[p[i]];
227 }
228 return -1;
229 }
230
blockHasMonsters(uint16 block)231 bool EoBCoreEngine::blockHasMonsters(uint16 block) {
232 return _levelBlockProperties[block].flags & 7 ? true : false;
233 }
234
isMonsterOnPos(EoBMonsterInPlay * m,uint16 block,int pos,int checkPos4)235 bool EoBCoreEngine::isMonsterOnPos(EoBMonsterInPlay *m, uint16 block, int pos, int checkPos4) {
236 return (m->block == block && (m->pos == pos || (m->pos == 4 && checkPos4))) ? true : false;
237 }
238
findBlockMonsters(uint16 block,int pos,int dir,int blockDamage,int singleTargetCheckAdjacent)239 const int16 *EoBCoreEngine::findBlockMonsters(uint16 block, int pos, int dir, int blockDamage, int singleTargetCheckAdjacent) {
240 static const uint8 cpos4[] = { 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 0, 1, 0, 1 };
241 int include4 = (pos < 4) ? cpos4[(dir << 2) + pos] : 1;
242 int16 *dst = _foundMonstersArray;
243
244 if (blockDamage) {
245 for (int i = 0; i < 30; i++) {
246 if (_monsters[i].block == block && (_monsters[i].pos != 4 || include4))
247 *dst++ = i;
248 }
249
250 } else if (singleTargetCheckAdjacent) {
251 int16 r = -1;
252 int f = 5;
253
254 for (int i = 0; i < 30; i++) {
255 const uint8 *tbl = &_findBlockMonstersTable[(dir << 4) + (pos << 2)];
256
257 if (_monsters[i].block != block)
258 continue;
259
260 if (_monsters[i].pos == pos) {
261 r = i;
262 break;
263 }
264
265 for (int ii = 0; ii < 4; ii++) {
266 if (_monsters[i].pos == tbl[ii] && ii < f) {
267 f = ii;
268 r = i;
269 }
270 }
271 }
272
273 *dst++ = r;
274
275 } else {
276 for (int i = 0; i < 30; i++) {
277 if (isMonsterOnPos(&_monsters[i], block, pos, include4))
278 *dst++ = i;
279 }
280 }
281
282 *dst = -1;
283 return _foundMonstersArray;
284 }
285
drawBlockObject(int flipped,int page,const uint8 * shape,int x,int y,int sd,uint8 * ovl)286 void EoBCoreEngine::drawBlockObject(int flipped, int page, const uint8 *shape, int x, int y, int sd, uint8 *ovl) {
287 const ScreenDim *d = _screen->getScreenDim(sd);
288 if (_flags.gameID == GI_EOB1)
289 x &= ~1;
290
291 _screen->drawShape(page, shape, x - (d->sx << 3) + _shapeShakeOffsetX, y - d->sy + _shapeShakeOffsetY, sd, flipped | (ovl ? 2 : 0), ovl);
292 }
293
drawMonsterShape(const uint8 * shape,int x,int y,int flipped,int flags,int palIndex)294 void EoBCoreEngine::drawMonsterShape(const uint8 *shape, int x, int y, int flipped, int flags, int palIndex) {
295 uint8 *ovl = 0;
296
297 if (flags & 2)
298 ovl = _monsterFlashOverlay;
299 else if (_flags.gameID == GI_EOB2 && flags & 0x20)
300 ovl = _monsterStoneOverlay;
301 else if (palIndex != -1 && _flags.platform != Common::kPlatformAmiga)
302 ovl = _monsterPalettes[palIndex];
303
304 drawBlockObject(flipped, 2, shape, x, y, 5, ovl);
305 }
306
flashMonsterShape(EoBMonsterInPlay * m)307 void EoBCoreEngine::flashMonsterShape(EoBMonsterInPlay *m) {
308 disableSysTimer(2);
309 _flashShapeTimer = 0;
310 drawScene(1);
311 m->flags &= 0xFD;
312 _flashShapeTimer = _system->getMillis() + _tickLength;
313 enableSysTimer(2);
314
315 _sceneUpdateRequired = true;
316 }
317
updateAllMonsterShapes()318 void EoBCoreEngine::updateAllMonsterShapes() {
319 drawScene(1);
320 bool updateShp = false;
321
322 for (EoBMonsterInPlay *m = _monsters; m < &_monsters[30]; m++) {
323 if (m->flags & 2) {
324 m->flags &= ~2;
325 updateShp = true;
326 if (m->hitPointsCur <= 0)
327 killMonster(m, true);
328 }
329 }
330
331 if (updateShp) {
332 _sceneUpdateRequired = true;
333 _flashShapeTimer = _system->getMillis() + _tickLength;
334 } else {
335 _sceneUpdateRequired = false;
336 }
337 _preventMonsterFlash = false;
338 }
339
drawBlockItems(int index)340 void EoBCoreEngine::drawBlockItems(int index) {
341 uint16 o = _visibleBlocks[index]->drawObjects;
342 uint8 w = _visibleBlocks[index]->walls[_sceneDrawVarDown];
343 uint8 flg = (index == 16) ? 0x80 : _wllWallFlags[w];
344
345 if (_wllVmpMap[w] && !(flg & 0x80))
346 return;
347
348 uint16 o2 = o = _items[o].next;
349 static const int8 itemPosYNiche[] = { 0x25, 0x31, 0x38, 0x00 };
350 static const int8 itemPosFin[] = { 0, -2, 1, -1, 2, 0, 1, -1 };
351 int tile2 = 0;
352
353 for (bool loop = true; o != o2 || loop; ) {
354 EoBItem *itm = &_items[o];
355 if (itm->pos == 8 || itm->pos < 4) {
356 tile2 = -1;
357
358 uint8 ps = (itm->pos == 8) ? 4 : _dscItemPosIndex[(_currentDirection << 2) + (itm->pos & 3)];
359 uint16 wo = (index * 5 + ps) << 1;
360 int x = _dscShapeCoords[wo] + 88;
361 int y = 0;
362
363 if (itm->pos == 8) {
364 x = _dscItemShpX[index];
365
366 if (_flags.gameID == Common::kPlatformSegaCD && _currentLevel == 12 && (_currentBlock & 0x1F) < 17 && (_currentBlock >> 5) < 20) {
367 if (index == 8)
368 x += 20;
369 else if (index == 10)
370 x -= 20;
371 }
372
373 y = itemPosYNiche[_dscDimMap[index]];
374 ps = 0;
375 } else {
376 y = _dscShapeCoords[wo + 1] + 124;
377 }
378
379 int8 scaleSteps = (int8)_dscItemScaleIndex[(_dscDimMap[index] << 2) + ps];
380 if ((flg & 8) && ps < 2 && scaleSteps) {
381 tile2 = _dscItemTileIndex[index];
382 if (tile2 != -1)
383 setLevelShapesDim(tile2, _shpDmX1, _shpDmX2, 5);
384 y -= 4;
385 }
386
387 if (scaleSteps >= 0) {
388 const uint8 *shp = 0;
389 if (_flags.gameID == GI_EOB2 || scaleSteps == 0)
390 shp = _screen->scaleShape(_dscItemShapeMap[itm->icon] < _numLargeItemShapes ? _largeItemShapes[_dscItemShapeMap[itm->icon]] : (_dscItemShapeMap[itm->icon] < 15 ? 0 : _smallItemShapes[_dscItemShapeMap[itm->icon] - 15]), scaleSteps);
391 else
392 shp = _dscItemShapeMap[itm->icon] < _numLargeItemShapes ? _largeItemShapesScl[scaleSteps - 1][_dscItemShapeMap[itm->icon]] : (_dscItemShapeMap[itm->icon] < 15 ? 0 : _smallItemShapesScl[scaleSteps - 1][_dscItemShapeMap[itm->icon] - 15]);
393
394 x = x + (itemPosFin[o & 7] << 1) - ((shp[2] << 3) >> 1);
395 y -= shp[1];
396
397 if (itm->pos != 8)
398 y += itemPosFin[(o >> 1) & 7];
399
400 drawBlockObject(0, 2, shp, x, y, 5);
401 _screen->setShapeFadingLevel(0);
402 }
403 }
404
405 o = itm->next;
406 loop = false;
407 if (tile2 != -1)
408 setLevelShapesDim(index, _shpDmX1, _shpDmX2, 5);
409 }
410 }
411
drawDoor(int index)412 void EoBCoreEngine::drawDoor(int index) {
413 int s = _visibleBlocks[index]->walls[_sceneDrawVarDown];
414
415 if (_flags.gameID == GI_EOB1 && s == 0x85)
416 s = 0;
417
418 if (s >= _dscDoorShpIndexSize)
419 return;
420
421 int type = _dscDoorShpIndex[s];
422 int d = _dscDimMap[index];
423 int w = _dscShapeCoords[(index * 5 + 4) << 1];
424
425 int x = 88 + w;
426 int y = 0;
427
428 int16 y1 = 0;
429 int16 y2 = 0;
430 setDoorShapeDim(index, y1, y2, 5);
431 drawDoorIntern(type, index, x, y, w, s, d, y1, y2);
432 drawLevelModifyScreenDim(5, _shpDmX1, 0, _shpDmX2, 15);
433 }
434
drawMonsters(int index)435 void EoBCoreEngine::drawMonsters(int index) {
436 static const uint8 distMap[] = { 2, 1, 0, 4 };
437 // SEGA: 2, 1, 0, 3 ??
438 static const uint8 yAdd[] = { 20, 12, 4, 4, 2, 0, 0 };
439
440 int blockDistance = distMap[_dscDimMap[index]];
441
442 uint16 bl = _visibleBlockIndex[index];
443 if (!bl)
444 return;
445
446 int drawObjDirIndex = _currentDirection * 5;
447 int cDirOffs = _currentDirection << 2;
448
449 EoBMonsterInPlay *drawObj[5];
450 memset(drawObj, 0, 5 * sizeof(EoBMonsterInPlay *));
451
452 for (int i = 0; i < 30; i++) {
453 if (_monsters[i].block != bl)
454 continue;
455 drawObj[_drawObjPosIndex[drawObjDirIndex + _monsters[i].pos]] = &_monsters[i];
456 }
457
458 for (int i = 0; i < 5; i++) {
459 EoBMonsterInPlay *d = drawObj[i];
460 if (!d)
461 continue;
462
463 EoBMonsterProperty *p = &_monsterProps[d->type];
464
465 if (_flags.gameID == GI_EOB2 && (p->capsFlags & 0x100) && !(_partyEffectFlags & 0x220) && !(d->flags & 2))
466 continue;
467
468 int f = (d->animStep << 4) + cDirOffs + d->dir;
469 f = (p->capsFlags & 2) ? _monsterFrmOffsTable1[f] : _monsterFrmOffsTable2[f];
470
471 if (!blockDistance && d->curAttackFrame < 0)
472 f = d->curAttackFrame + 7;
473
474 int subFrame = ABS(f);
475 int shpIndex = d->shpIndex ? 18 : 0;
476 int palIndex = d->palette ? ((((shpIndex == 18) ? subFrame + 5 : subFrame - 1) << 1) + (d->palette - 1)) : -1;
477 int shpOffs = subFrame + shpIndex - 1;
478 int xAdd2 = 0;
479 int yAdd2 = 0;
480
481 int v30 = (subFrame == 1 || subFrame > 3) ? 1 : 0;
482 int posOffs = (d->pos == 4) ? 4 : _dscItemPosIndex[cDirOffs + d->pos];
483 int posIndex = (index * 5 + posOffs) << 1;
484
485 if (_flags.platform == Common::kPlatformSegaCD) {
486 if (d->curAttackFrame < 0)
487 subFrame = 5;
488 else if (subFrame >= 3)
489 subFrame--;
490
491 if (d->animType != subFrame) {
492 d->animType = subFrame;
493 d->animProgress = 0;
494 }
495 } else if (d->curAttackFrame < 0) {
496 d->curAttackFrame++;
497 }
498
499 for (int numFrames = 1; numFrames; --numFrames) {
500 if (_flags.platform == Common::kPlatformSegaCD) {
501 int temp = 0;
502 const uint8 *frm = _staticres->loadRawData(kEoB1MonsterAnimFrames00 + d->type * 5 + subFrame - 1, temp) + ((d->animProgress++) << 2);
503 shpOffs = shpIndex + (frm[0] & 0x3F);
504 numFrames += ((frm[0] >> 6) & 1);
505 xAdd2 = (int8)frm[1];
506 yAdd2 = (int8)frm[2];
507 if (frm[4] == 0xFE) {
508 d->animProgress = 0;
509 } else if (frm[4] == 0xFF) {
510 d->curAttackFrame = 0;
511 d->animType = 0;
512 }
513 }
514
515 const uint8 *shp = _screen->scaleShape(_monsterShapes[shpOffs], blockDistance);
516
517 int x = _dscShapeCoords[posIndex] + 88;
518 int y = _dscShapeCoords[posIndex + 1] + 127;
519
520 if (p->u30 == 1) {
521 if (v30) {
522 if (_flags.gameID == GI_EOB2)
523 posIndex = ((posIndex >> 1) - posOffs) << 1;
524 y = _dscShapeCoords[posIndex + 1] + 127 + yAdd[blockDistance + ((posOffs == 4 || _flags.gameID == GI_EOB1) ? 0 : 3)];
525 } else {
526 if (_flags.gameID == GI_EOB2)
527 posIndex = ((posIndex >> 1) - posOffs + 4) << 1;
528 x = _dscShapeCoords[posIndex] + 88;
529 }
530 }
531
532 int w = shp[2] << 3;
533 int h = shp[1];
534
535 x = x - (w >> 1) + (d->idleAnimState >> 4) + xAdd2;
536 y = y - h + (d->idleAnimState & 0x0F) + yAdd2;
537
538 drawMonsterShape(shp, x, y, f >= 0 ? 0 : 1, d->flags, palIndex);
539
540 if (_flags.gameID == GI_EOB2) {
541 for (int ii = 0; ii < 3; ii++) {
542 if (!p->decorations[ii])
543 continue;
544
545 SpriteDecoration *dcr = &_monsterDecorations[(p->decorations[ii] - 1) * 6 + subFrame + shpIndex - 1];
546
547 if (!dcr->shp)
548 continue;
549
550 shp = _screen->scaleShape(dcr->shp, blockDistance);
551 int dx = dcr->x;
552 int dy = dcr->y;
553
554 for (int iii = 0; iii < blockDistance; iii++) {
555 dx = (dx << 1) / 3;
556 dy = (dy << 1) / 3;
557 }
558
559 drawMonsterShape(shp, x + ((f < 0) ? (w - dx - (shp[2] << 3)) : dx), y + dy, f >= 0 ? 0 : 1, d->flags, -1);
560 }
561 }
562 _screen->setShapeFadingLevel(0);
563 }
564 }
565 }
566
drawWallOfForce(int index)567 void EoBCoreEngine::drawWallOfForce(int index) {
568 int d = _dscDimMap[index];
569 assert(d < 3);
570 int dH = _wallOfForceDsNumH[d];
571 int dW = _wallOfForceDsNumW[d];
572 int y = _wallOfForceDsY[d];
573 int shpId = _wallOfForceShpId[d] + _teleporterPulse;
574 int h = _wallOfForceShapes[shpId][1];
575 int w = _wallOfForceShapes[shpId][2] << 3;
576
577 for (int i = 0; i < dH; i++) {
578 int x = _wallOfForceDsX[index];
579 for (int ii = 0; ii < dW; ii++) {
580 drawBlockObject(0, 2, _wallOfForceShapes[shpId], x, y, 5);
581 x += w;
582 }
583 y += h;
584 shpId ^= 1;
585 }
586 }
587
drawFlyingObjects(int index)588 void EoBCoreEngine::drawFlyingObjects(int index) {
589 LevelBlockProperty *bl = _visibleBlocks[index];
590 int blockIndex = _visibleBlockIndex[index];
591 int w = bl->walls[_sceneDrawVarDown];
592
593 if (_wllVmpMap[w] && !(_wllWallFlags[w] & 0x80))
594 return;
595
596 EoBFlyingObject *drawObj[5];
597 memset(drawObj, 0, 5 * sizeof(EoBFlyingObject *));
598
599 for (int i = 0; i < 10; i++) {
600 if (!_flyingObjects[i].enable || blockIndex != _flyingObjects[i].curBlock)
601 continue;
602 drawObj[_drawObjPosIndex[_currentDirection * 5 + (_flyingObjects[i].curPos & 3)]] = &_flyingObjects[i];
603 }
604
605 for (int i = 0; i < 5; i++) {
606 EoBFlyingObject *fo = drawObj[i];
607 if (!fo)
608 continue;
609
610 int p = _dscItemPosIndex[(_currentDirection << 2) + (fo->curPos & 3)];
611 int x = _dscShapeCoords[(index * 5 + p) << 1] + 88;
612 int y = 39;
613
614 int sclValue = _flightObjSclIndex[(index << 2) + p];
615 int flipped = 0;
616
617 if (sclValue < 0) {
618 _screen->setShapeFadingLevel(0);
619 continue;
620 }
621
622 const uint8 *shp = 0;
623 bool noFade = false;
624
625 if (fo->enable == 1) {
626 int shpIx = _dscItemShapeMap[_items[fo->item].icon];
627 int dirOffs = (fo->direction == _currentDirection) ? 0 : ((fo->direction == (_currentDirection ^ 2)) ? 1 : -1);
628
629 if (dirOffs == -1 || _flightObjShpMap[shpIx] == -1) {
630 if (_flags.gameID == GI_EOB2 || sclValue == 0)
631 shp = shpIx < _numLargeItemShapes ? _largeItemShapes[shpIx] : (shpIx < 15 ? 0 : _smallItemShapes[shpIx - 15]);
632 else
633 shp = shpIx < _numLargeItemShapes ? _largeItemShapesScl[sclValue - 1][shpIx] : (shpIx < 15 ? 0 : _smallItemShapesScl[sclValue - 1][shpIx - 15]);
634 flipped = fo->direction == ((_currentDirection + 1) & 3) ? 1 : 0;
635 } else {
636 if (_flags.gameID == GI_EOB2 || sclValue == 0)
637 shp = (_flightObjShpMap[shpIx] + dirOffs) < _numThrownItemShapes ? _thrownItemShapes[_flightObjShpMap[shpIx] + dirOffs] : _spellShapes[_flightObjShpMap[shpIx - _numThrownItemShapes] + dirOffs];
638 else
639 shp = (_flightObjShpMap[shpIx] + dirOffs) < _numThrownItemShapes ? _thrownItemShapesScl[sclValue - 1][_flightObjShpMap[shpIx] + dirOffs] : 0;
640 flipped = _flightObjFlipIndex[(fo->direction << 2) + (fo->curPos & 3)];
641 }
642
643 } else {
644 noFade = true;
645 if (_flags.gameID == GI_EOB2 || sclValue == 0)
646 shp = (fo->objectType < _numThrownItemShapes) ? _thrownItemShapes[fo->objectType] : _spellShapes[fo->objectType - _numThrownItemShapes];
647 else
648 shp = (fo->objectType < _numThrownItemShapes) ? _thrownItemShapesScl[sclValue - 1][fo->objectType] : 0;
649 flipped = _flightObjFlipIndex[(fo->direction << 2) + (fo->curPos & 3)];
650
651 if (fo->flags & 0x40) {
652 x = _dscShapeCoords[(index * 5 + 4) << 1] + 88;
653 y = 44;
654 }
655 }
656
657 assert(shp);
658
659 if (_flags.gameID == GI_EOB2 || sclValue == 0)
660 shp = _screen->scaleShape(shp, sclValue);
661
662 if (noFade) {
663 _screen->setShapeFadingLevel(0);
664 noFade = false;
665 }
666
667 x -= (shp[2] << 2);
668 y -= (y == 44 ? (shp[1] >> 1) : shp[1]);
669
670 drawBlockObject(flipped, 2, shp, x, y, 5);
671 _screen->setShapeFadingLevel(0);
672 }
673 }
674
drawTeleporter(int index)675 void EoBCoreEngine::drawTeleporter(int index) {
676 static const uint8 telprtX[] = { 0x28, 0x1C, 0x12 };
677 static const uint8 telprtY[] = { 0x0D, 0x15, 0x1A };
678
679 int t = 2 - _dscDimMap[index];
680 if (t < 0)
681 return;
682
683 int16 x1 = _dscItemShpX[index] - telprtX[t];
684 int16 y1 = telprtY[t];
685
686 for (int i = 0; i < 2; i++) {
687 int16 x2 = 0;
688 int16 y2 = 0;
689 int d = (t << 1) + i;
690 if (!d)
691 x2 = y2 = -4;
692
693 const uint8 *shp = _teleporterShapes[d ^ _teleporterPulse];
694
695 for (int ii = 0; ii < 13; ii++)
696 drawBlockObject(0, 2, shp, x1 + x2 + _teleporterShapeCoords[d * 26 + ii * 2], y1 + y2 + _teleporterShapeCoords[d * 26 + ii * 2 + 1], 5);
697 }
698 }
699
updateMonsters(int unit)700 void EoBCoreEngine::updateMonsters(int unit) {
701 for (int i = 0; i < 30; i++) {
702 EoBMonsterInPlay *m = &_monsters[i];
703 if (m->unit == unit) {
704 if (m->hitPointsCur <= 0 || m->flags & 0x20)
705 continue;
706 if (m->directionChanged) {
707 m->directionChanged = 0;
708 continue;
709 }
710
711 updateMonsterDest(m);
712
713 if (m->mode > 0)
714 updateMonsterAttackMode(m);
715
716 switch (m->mode) {
717 case 0:
718 updateMoveMonster(m);
719 break;
720 case 1:
721 updateMonsterFollowPath(m, 2);
722 break;
723 case 2:
724 updateMonsterFollowPath(m, -1);
725 break;
726 case 3:
727 updateMonsterFollowPath(m, 1);
728 break;
729 case 5:
730 updateMonstersStraying(m, -1);
731 break;
732 case 6:
733 updateMonstersStraying(m, 1);
734 break;
735 case 7:
736 case 10:
737 updateMonstersSpellStatus(m);
738 break;
739 default:
740 break;
741 }
742
743 if (m->mode != 4 && m->mode != 7 && m->mode != 8)
744 m->animStep ^= 1;
745
746 if (_monsterProps[m->type].u30 == 1)
747 setBlockMonsterDirection(m->block, m->dir);
748 }
749 }
750 checkFlyingObjects();
751 }
752
updateMonsterDest(EoBMonsterInPlay * m)753 void EoBCoreEngine::updateMonsterDest(EoBMonsterInPlay *m) {
754 if (m->mode >= 7 && m->mode <= 10)
755 return;
756 int dist = getBlockDistance(m->block, _currentBlock);
757 if (dist >= 4)
758 return;
759
760 int s = getNextMonsterDirection(m->block, _currentBlock) - (m->dir << 1) - 3;
761
762 if (s < 0)
763 s += 8;
764
765 if (s <= 2 && dist >= 2)
766 return;
767
768 m->mode = 0;
769 m->dest = _currentBlock;
770 }
771
updateMonsterAttackMode(EoBMonsterInPlay * m)772 void EoBCoreEngine::updateMonsterAttackMode(EoBMonsterInPlay *m) {
773 if (!(m->flags & 1) || m->mode == 10)
774 return;
775 if (m->mode == 8) {
776 turnFriendlyMonstersHostile();
777 return;
778 }
779 m->mode = 0;
780 m->dest = _currentBlock;
781 }
782
updateAllMonsterDests()783 void EoBCoreEngine::updateAllMonsterDests() {
784 for (int i = 0; i < 30; i++)
785 updateMonsterDest(&_monsters[i]);
786 }
787
turnFriendlyMonstersHostile()788 void EoBCoreEngine::turnFriendlyMonstersHostile() {
789 EoBMonsterInPlay *m = 0;
790 for (int i = 0; i < 30; i++) {
791 if (_monsters[i].mode == 8) {
792 _monsters[i].mode = 0;
793 _monsters[i].dest = _currentBlock;
794 m = &_monsters[i];
795 }
796 }
797
798 if (m) {
799 if (m->type == 7)
800 setScriptFlags(0x40000);
801 else if (m->type == 12)
802 setScriptFlags(0x8000000);
803 }
804 }
805
getNextMonsterDirection(int curBlock,int destBlock)806 int EoBCoreEngine::getNextMonsterDirection(int curBlock, int destBlock) {
807 uint8 c = destBlock % 32;
808 uint8 d = destBlock / 32;
809 uint8 e = curBlock % 32;
810 uint8 f = curBlock / 32;
811
812 int r = 0;
813
814 int s1 = (_flags.platform == Common::kPlatformAmiga) ? (d - f) : (f - d);
815 int d1 = ABS(s1);
816 s1 <<= 1;
817 int s2 = c - e;
818 int d2 = ABS(s2);
819 s2 <<= 1;
820
821 if (s1 >= d2)
822 r |= 8;
823 if (-s1 >= d2)
824 r |= 4;
825 if (s2 >= d1)
826 r |= 2;
827 if (-s2 >= d1)
828 r |= 1;
829
830 return _monsterDirChangeTable[r];
831 }
832
getNextMonsterPos(EoBMonsterInPlay * m,int block)833 int EoBCoreEngine::getNextMonsterPos(EoBMonsterInPlay *m, int block) {
834 if ((_flags.gameID == GI_EOB1 && _monsterProps[m->type].u30 != 0) || (_flags.gameID == GI_EOB2 && _monsterProps[m->type].u30 == 2))
835 return -1;
836 int d = findFreeMonsterPos(block, _monsterProps[m->type].u30);
837 if (d < 0)
838 return -1;
839
840 int dir = m->dir;
841 if (_flags.gameID == GI_EOB2) {
842 if (_monsterProps[m->type].u30 == 1) {
843 if (d == 9)
844 return -1;
845
846 int v = _monsterCloseAttUnkTable[d];
847 if (v != -1)
848 //////
849 m->dir = 0;
850 return v;
851 }
852 } else {
853 dir &= 1;
854 }
855
856 for (int i = 0; i < 4; i++) {
857 int v = m->dir ^ _monsterCloseAttPosTable2[(dir << 2) + i];
858 if (!(d & (1 << v)))
859 return v;
860 }
861
862 return -1;
863 }
864
findFreeMonsterPos(int block,int size)865 int EoBCoreEngine::findFreeMonsterPos(int block, int size) {
866 int nm = _levelBlockProperties[block].flags & 7;
867 if (nm == 4)
868 return -2;
869
870 int res = 0;
871
872 for (int i = 0; i < 30; i++) {
873 EoBMonsterInPlay *m = &_monsters[i];
874 if (m->block != block)
875 continue;
876 if (_monsterProps[m->type].u30 != size)
877 return -1;
878
879 if (m->pos == 4 && !(_flags.gameID == GI_EOB2 && m->flags & 0x20))
880 m->pos = (_flags.gameID == GI_EOB2 && _monsterProps[m->type].u30 == 1) ? 0 : _monsterCloseAttPosTable1[m->dir];
881
882 res |= (1 << m->pos);
883 if (--nm == 0)
884 break;
885 }
886
887 return res;
888 }
889
updateMoveMonster(EoBMonsterInPlay * m)890 void EoBCoreEngine::updateMoveMonster(EoBMonsterInPlay *m) {
891 EoBMonsterProperty *p = &_monsterProps[m->type];
892 int d = getNextMonsterDirection(m->block, _currentBlock);
893
894 if ((_flags.gameID == GI_EOB2) && (p->capsFlags & 0x800) && !(d & 1))
895 d >>= 1;
896 else
897 d = m->dir;
898
899 d = calcNewBlockPosition(m->block, d);
900
901 if (m->dest == d && _currentBlock != d) {
902 m->mode = rollDice(1, 2, -1) + 5;
903 return;
904 }
905
906 if (updateMonsterTryDistanceAttack(m))
907 return;
908
909 if (updateMonsterTryCloseAttack(m, d))
910 return;
911
912 m->curAttackFrame = 0;
913 walkMonster(m, m->dest);
914
915 if (p->capsFlags & 8)
916 updateMonsterTryCloseAttack(m, -1);
917 }
918
updateMonsterTryDistanceAttack(EoBMonsterInPlay * m)919 bool EoBCoreEngine::updateMonsterTryDistanceAttack(EoBMonsterInPlay *m) {
920 EoBMonsterProperty *p = &_monsterProps[m->type];
921 if (!m->numRemoteAttacks || ((_flags.gameID == GI_EOB1) && !(p->capsFlags & 0x40)))
922 return false;
923
924 if ((_flags.gameID == GI_EOB1 && m->stepsTillRemoteAttack < 5) || (_flags.gameID == GI_EOB2 && (rollDice(1, 3) > m->stepsTillRemoteAttack))) {
925 m->stepsTillRemoteAttack++;
926 return false;
927 }
928
929 if (getBlockDistance(m->block, _currentBlock) > 3 || getNextMonsterDirection(m->block, _currentBlock) != (m->dir << 1))
930 return false;
931
932 int d = m->dir;
933 int bl = calcNewBlockPosition(m->block, d);
934
935 while (bl != _currentBlock) {
936 if (!(_wllWallFlags[_levelBlockProperties[bl].walls[d ^ 2]] & 3) || (_levelBlockProperties[bl].flags & 7))
937 return false;
938 bl = calcNewBlockPosition(bl, d);
939 }
940
941 Item itm = 0;
942 if (_flags.gameID == GI_EOB1) {
943 switch (m->type - 4) {
944 case 0:
945 launchMagicObject(-1, 9, m->block, m->pos, m->dir);
946 snd_processEnvironmentalSoundEffect(31, m->block);
947 break;
948 case 10:
949 launchMagicObject(-1, _enemyMageSpellList[m->numRemoteAttacks], m->block, m->pos, m->dir);
950 snd_processEnvironmentalSoundEffect(_enemyMageSfx[m->numRemoteAttacks], m->block);
951 break;
952 case 11:
953 itm = duplicateItem(60);
954 if (itm) {
955 if (!launchObject(-1, itm, m->block, m->pos, m->dir, _items[itm].type))
956 _items[itm].block = -1;
957 }
958 break;
959 case 12:
960 launchMagicObject(-1, 0, m->block, m->pos, m->dir);
961 snd_processEnvironmentalSoundEffect(85, m->block);
962 break;
963 case 13:
964 snd_processEnvironmentalSoundEffect(83, m->block);
965 _txt->printMessage(_monsterSpecAttStrings[1]);
966 for (int i = 0; i < 6; i++)
967 statusAttack(i, 4, _monsterSpecAttStrings[2], 1, 5, 9, 1);
968 break;
969 case 17:
970 d = rollDice(1, 4, -1);
971 if (d >= 3) {
972 for (int i = 0; i < 6; i++) {
973 if (!testCharacter(i, 3))
974 continue;
975 _txt->printMessage(_monsterSpecAttStrings[0], -1, _characters[i].name);
976 inflictCharacterDamage(i, rollDice(2, 8, 1));
977 }
978 snd_processEnvironmentalSoundEffect(108, m->block);
979 } else {
980 launchMagicObject(-1, _beholderSpellList[d], m->block, m->pos, m->dir);
981 snd_processEnvironmentalSoundEffect(_beholderSfx[d], m->block);
982 }
983 break;
984 default:
985 break;
986 }
987
988 } else {
989 int cw = 0;
990 if (p->remoteWeaponChangeMode == 1) {
991 cw = m->curRemoteWeapon++;
992 if (m->curRemoteWeapon == p->numRemoteWeapons)
993 m->curRemoteWeapon = 0;
994 } else if (p->remoteWeaponChangeMode == 2) {
995 cw = rollDice(1, p->numRemoteWeapons, -1);
996 }
997
998 int s = p->remoteWeapons[cw];
999 if (s >= 0) {
1000 if (s < 20) {
1001 monsterSpellCast(m, s);
1002 } else if (s == 20) {
1003 if (_flags.platform == Common::kPlatformAmiga)
1004 snd_processEnvironmentalSoundEffect(39, _currentBlock + 1);
1005 else
1006 snd_processEnvironmentalSoundEffect(103, m->block);
1007 _txt->printMessage(_monsterSpecAttStrings[0]);
1008 for (int i = 0; i < 6; i++)
1009 statusAttack(i, 4, _monsterSpecAttStrings[1], 1, 5, 9, 1);
1010 }
1011 } else {
1012 itm = duplicateItem(-s);
1013 if (itm) {
1014 if (!launchObject(-1, itm, m->block, m->pos, m->dir, _items[itm].type))
1015 _items[itm].block = -1;
1016 }
1017 }
1018 }
1019
1020 if (m->numRemoteAttacks != 255)
1021 m->numRemoteAttacks--;
1022 m->stepsTillRemoteAttack = 0;
1023 return true;
1024 }
1025
updateMonsterTryCloseAttack(EoBMonsterInPlay * m,int block)1026 bool EoBCoreEngine::updateMonsterTryCloseAttack(EoBMonsterInPlay *m, int block) {
1027 if (block == -1)
1028 block = calcNewBlockPosition(m->block, m->dir);
1029
1030 if (block != _currentBlock)
1031 return false;
1032
1033 int r = (m->pos == 4 || (_flags.gameID == GI_EOB2 && _monsterProps[m->type].u30 == 1)) ? 1 : _monsterCloseAttChkTable1[(m->dir << 2) + m->pos];
1034
1035 if (r) {
1036 m->flags ^= 4;
1037 if (!(m->flags & 4))
1038 return true;
1039
1040 bool facing = (m->block == _visibleBlockIndex[13]);
1041
1042 if (facing) {
1043 disableSysTimer(2);
1044 if ((_flags.platform == Common::kPlatformSegaCD) == (m->type != 4))
1045 snd_updateEnvironmentalSfx(_monsterProps[m->type].sound1);
1046
1047 _flashShapeTimer = _flashShapeTimerIntv0;
1048 m->curAttackFrame = -2;
1049
1050 for (int i = 0; i < 16 && m->curAttackFrame < 0; ++i) {
1051 if (m->type != 4 && m->curAttackFrame == -1)
1052 snd_updateEnvironmentalSfx(_monsterProps[m->type].sound1);
1053 if (_flags.platform == Common::kPlatformSegaCD && _partyResting) {
1054 // The original SegaCD code does not update the monsters during resting. I presume to
1055 // avoid graphical issues which I try to fix here...
1056 setLevelPalettes(_currentLevel);
1057 _screen->sega_selectPalette(-1, 2, true);
1058 gui_setupPlayFieldHelperPages(true);
1059 gui_drawAllCharPortraitsWithStats();
1060 _partyResting = false;
1061 }
1062 drawScene(1);
1063 _flashShapeTimer = _system->getMillis() + _flashShapeTimerIntv1;
1064 }
1065
1066 } else {
1067 snd_updateEnvironmentalSfx(_monsterProps[m->type].sound1);
1068 }
1069
1070 monsterCloseAttack(m);
1071
1072 if (facing) {
1073 m->curAttackFrame = 0;
1074 m->animStep ^= 1;
1075 _sceneUpdateRequired = 1;
1076 enableSysTimer(2);
1077 _flashShapeTimer = _system->getMillis() + _flashShapeTimerIntv2;
1078 }
1079 } else {
1080 int b = m->block;
1081 if ((_levelBlockProperties[b].flags & 7) == 1) {
1082 m->pos = 4;
1083 } else {
1084 b = getNextMonsterPos(m, b);
1085 if (b >= 0)
1086 m->pos = b;
1087 }
1088 checkSceneUpdateNeed(m->block);
1089 }
1090
1091 return true;
1092 }
1093
walkMonster(EoBMonsterInPlay * m,int destBlock)1094 void EoBCoreEngine::walkMonster(EoBMonsterInPlay *m, int destBlock) {
1095 if (++_monsterStepCounter > 10) {
1096 _monsterStepCounter = 0;
1097 _monsterStepMode ^= 1;
1098 }
1099
1100 const int8 *tbl = _monsterStepMode ? _monsterStepTable3 : _monsterStepTable2;
1101
1102 int s = m->dir << 1;
1103 int b = m->block;
1104 int d = getNextMonsterDirection(b, destBlock);
1105 if (d == -1)
1106 return;
1107
1108 if (m->flags & 8) {
1109 // Interestingly, the fear spell in EOB 1 does not expire.
1110 // I don't know whether this is intended or not.
1111 if (_flags.gameID == GI_EOB1) {
1112 d ^= 4;
1113 } else if (m->spellStatusLeft > 0) {
1114 if (--m->spellStatusLeft == 0)
1115 m->flags &= ~8;
1116 else
1117 d ^= 4;
1118 }
1119 }
1120
1121 int d2 = (d - s) & 7;
1122
1123 if (_flags.gameID == GI_EOB1) {
1124 if ((b + _monsterStepTable0[d >> 1] == _currentBlock) && !(d & 1)) {
1125 if (d2 >= 5)
1126 s = m->dir - 1;
1127 else if (d2 != 0)
1128 s = m->dir + 1;
1129 walkMonsterNextStep(m, -1, s & 3);
1130 return;
1131 }
1132 } else if (_flags.gameID == GI_EOB2) {
1133 if (b + _monsterStepTable0[d] == destBlock) {
1134 if (d & 1) {
1135 int e = _monsterStepTable1[((d - 1) << 1) + m->dir];
1136 if (e && (!(_monsterProps[m->type].capsFlags & 0x200) || (rollDice(1, 4) < 4))) {
1137 if (walkMonsterNextStep(m, b + e, -1))
1138 return;
1139 }
1140 } else {
1141 walkMonsterNextStep(m, -1, d >> 1);
1142 return;
1143 }
1144 }
1145 }
1146
1147 if (d2) {
1148 if (d2 >= 5)
1149 s -= (1 + ((d & 1) ^ 1));
1150 else
1151 s += (1 + ((d & 1) ^ 1));
1152 s &= 7;
1153 }
1154
1155 for (int i = 7; i > -1; i--) {
1156 s = (s + tbl[i]) & 7;
1157 uint16 b2 = (s & 1) ? 0 : calcNewBlockPosition(b, s >> 1);
1158 if (!b2)
1159 continue;
1160 if (walkMonsterNextStep(m, b2, s >> 1))
1161 return;
1162 }
1163 }
1164
walkMonsterNextStep(EoBMonsterInPlay * m,int destBlock,int direction)1165 bool EoBCoreEngine::walkMonsterNextStep(EoBMonsterInPlay *m, int destBlock, int direction) {
1166 EoBMonsterProperty *p = &_monsterProps[m->type];
1167 int obl = m->block;
1168
1169 if (destBlock != m->block && destBlock != -1) {
1170 if (m->flags & 8) {
1171 if (getBlockDistance(destBlock, _currentBlock) < getBlockDistance(m->block, _currentBlock))
1172 return false;
1173 }
1174
1175 if (destBlock == _currentBlock)
1176 return false;
1177
1178 if (direction == -1)
1179 direction = m->dir;
1180
1181 LevelBlockProperty *l = &_levelBlockProperties[destBlock];
1182 uint8 w = l->walls[direction ^ 2];
1183
1184 if (!(_wllWallFlags[w] & 4)) {
1185 if (_flags.gameID == GI_EOB1 || !(p->capsFlags & 0x1000) || _wllShapeMap[w] != -1)
1186 return false;
1187
1188 if (_wllWallFlags[w] & 0x20) {
1189 if (p->capsFlags & 4 && m->type == 1)
1190 l->walls[direction] = l->walls[direction ^ 2] = 72;
1191 else
1192 openDoor(destBlock);
1193 }
1194
1195 if (direction != -1) {
1196 m->dir = direction;
1197 checkSceneUpdateNeed(m->block);
1198 }
1199 return true;
1200 }
1201
1202 if ((l->flags & 7) && destBlock) {
1203 int pos = getNextMonsterPos(m, destBlock);
1204 if (pos == -1)
1205 return false;
1206 m->pos = pos;
1207 }
1208
1209 placeMonster(m, destBlock, direction);
1210 direction = -1;
1211 }
1212
1213 if (direction != -1)
1214 m->dir = direction;
1215
1216 checkSceneUpdateNeed(obl);
1217 uint16 prioFlag = (_flags.platform == Common::kPlatformSegaCD) ? 0x2000 : 0;
1218 if (!_partyResting && p->sound2 > 0)
1219 snd_processEnvironmentalSoundEffect(p->sound2 | prioFlag, m->block);
1220
1221 return true;
1222 }
1223
updateMonsterFollowPath(EoBMonsterInPlay * m,int turnSteps)1224 void EoBCoreEngine::updateMonsterFollowPath(EoBMonsterInPlay *m, int turnSteps) {
1225 if (!walkMonsterNextStep(m, calcNewBlockPosition(m->block, m->dir), -1)) {
1226 m->dir = (m->dir + turnSteps) & 3;
1227 walkMonsterNextStep(m, -1, m->dir);
1228 }
1229 }
1230
updateMonstersStraying(EoBMonsterInPlay * m,int a)1231 void EoBCoreEngine::updateMonstersStraying(EoBMonsterInPlay *m, int a) {
1232 if (m->stray >= 0) {
1233 if (m->stray == 0)
1234 updateMonsterFollowPath(m, -a);
1235
1236 int8 d = (m->dir + a) & 3;
1237 uint16 bl = calcNewBlockPosition(m->block, d);
1238 uint8 flg = _wllWallFlags[_levelBlockProperties[bl].walls[_dscBlockMap[d]]] & 4;
1239
1240 if (m->stray == 0) {
1241 if (!flg)
1242 m->stray = -1;
1243 return;
1244 }
1245
1246 if (flg) {
1247 walkMonsterNextStep(m, -1, d);
1248 m->stray = -1;
1249 return;
1250 }
1251 }
1252
1253 if (walkMonsterNextStep(m, calcNewBlockPosition(m->block, m->dir), -1)) {
1254 m->stray = 1;
1255 } else {
1256 walkMonsterNextStep(m, -1, (m->dir - a) & 3);
1257 m->stray = 0;
1258 }
1259 }
1260
updateMonstersSpellStatus(EoBMonsterInPlay * m)1261 void EoBCoreEngine::updateMonstersSpellStatus(EoBMonsterInPlay *m) {
1262 if (m->spellStatusLeft) {
1263 if (!--m->spellStatusLeft)
1264 m->mode = 0;
1265 }
1266 }
1267
setBlockMonsterDirection(int block,int dir)1268 void EoBCoreEngine::setBlockMonsterDirection(int block, int dir) {
1269 for (int i = 0; i < 30; i++) {
1270 if (_monsters[i].block != block || _monsters[i].dir == dir)
1271 continue;
1272 _monsters[i].dir = dir;
1273 _monsters[i].directionChanged = 1;
1274 }
1275 }
1276
1277 } // End of namespace Kyra
1278
1279 #endif // ENABLE_EOB
1280