aboutsummaryrefslogtreecommitdiff
path: root/engines/kyra/sprites_lol.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'engines/kyra/sprites_lol.cpp')
-rw-r--r--engines/kyra/sprites_lol.cpp341
1 files changed, 305 insertions, 36 deletions
diff --git a/engines/kyra/sprites_lol.cpp b/engines/kyra/sprites_lol.cpp
index 7253d6ba32..76e14d44d4 100644
--- a/engines/kyra/sprites_lol.cpp
+++ b/engines/kyra/sprites_lol.cpp
@@ -162,9 +162,10 @@ int LoLEngine::disableMonstersForBlock(int block) {
void LoLEngine::setMonsterMode(MonsterInPlay *monster, int mode) {
if (monster->mode == 13 && mode != 14)
return;
+
if (mode == 7) {
monster->destX = _partyPosX;
- monster->destY = _partyPosX;
+ monster->destY = _partyPosY;
}
if (monster->mode == 1 && mode == 7) {
@@ -172,19 +173,19 @@ void LoLEngine::setMonsterMode(MonsterInPlay *monster, int mode) {
if (monster->mode != 1)
continue;
monster->mode = mode;
- monster->field_15 = 0;
+ monster->fightCurTick = 0;
monster->destX = _partyPosX;
monster->destY = _partyPosY;
setMonsterDirection(monster, calcMonsterDirection(monster->x, monster->y, monster->destX, monster->destY));
}
} else {
monster->mode = mode;
- monster->field_15 = 0;
+ monster->fightCurTick = 0;
if (mode == 14)
monster->might = 0;
if (mode == 13 && (monster->flags & 0x20)) {
monster->mode = 0;
- cmzS3(monster);
+ monsterDropItems(monster);
if (_currentLevel != 29)
setMonsterMode(monster, 14);
runLevelScriptCustom(0x404, -1, monster->id, monster->id, 0, 0);
@@ -195,6 +196,47 @@ void LoLEngine::setMonsterMode(MonsterInPlay *monster, int mode) {
}
}
+bool LoLEngine::updateMonsterAdjustBlocks(MonsterInPlay *monster) {
+ static const uint8 dims[] = { 0, 13, 9, 3 };
+ if (monster->properties->flags & 8)
+ return true;
+
+ uint16 x1 = (monster->x & 0xff00) | 0x80;
+ uint16 y1 = (monster->y & 0xff00) | 0x80;
+ int x2 = _partyPosX;
+ int y2 = _partyPosY;
+
+ uint16 dir = 0;
+ if (monster->properties->flags & 1) {
+ dir = monster->direction >> 1;
+ } else {
+ dir = calcMonsterDirection(x1, y1, x2, y2);
+ if ((monster->properties->flags & 2) && (dir == (monster->direction ^ 4)))
+ return false;
+ dir >>= 1;
+ }
+
+ calcSpriteRelPosition(x1, y1, x2, y2, dir);
+ x2 >>= 8;
+ y2 >>= 8;
+
+ if (y2 < 0 || y2 > 3)
+ return false;
+
+ int t = (x2 < 0) ? -x2 : x2;
+ if (t > y2)
+ return false;
+
+ for (int i = 0; i < 18; i++)
+ _curBlockCaps[i] = &_levelBlockProperties[(monster->blockPropertyIndex + _dscBlockIndex[dir + i]) & 0x3ff];
+
+ int16 fx1 = 0;
+ int16 fx2 = 0;
+ setLevelShapesDim(x2 + dims[y2], fx1, fx2, 13);
+
+ return (fx1 >= fx2) ? false : true;
+}
+
void LoLEngine::placeMonster(MonsterInPlay *monster, uint16 x, uint16 y) {
bool cont = true;
int t = monster->blockPropertyIndex;
@@ -211,7 +253,7 @@ void LoLEngine::placeMonster(MonsterInPlay *monster, uint16 x, uint16 y) {
if (monster->x != x || monster->y != y) {
monster->x = x;
monster->y = y;
- monster->anon9 = (++monster->anon9) & 3;
+ monster->currentSubFrame = (++monster->currentSubFrame) & 3;
}
if (monster->blockPropertyIndex == 0)
@@ -224,7 +266,7 @@ void LoLEngine::placeMonster(MonsterInPlay *monster, uint16 x, uint16 y) {
if (monster->properties->sounds[0] == 0 || cont == false)
return;
- if ((!(monster->properties->flags & 0x100) || ((monster->anon9 & 1) == 0)) && monster->blockPropertyIndex == t)
+ if ((!(monster->properties->flags & 0x100) || ((monster->currentSubFrame & 1) == 0)) && monster->blockPropertyIndex == t)
return;
if (monster->blockPropertyIndex != t)
@@ -238,6 +280,7 @@ void LoLEngine::placeMonster(MonsterInPlay *monster, uint16 x, uint16 y) {
int LoLEngine::calcMonsterDirection(uint16 x1, uint16 y1, uint16 x2, uint16 y2) {
int16 r = 0;
+
int16 t1 = y1 - y2;
if (t1 < 0) {
r++;
@@ -247,19 +290,15 @@ int LoLEngine::calcMonsterDirection(uint16 x1, uint16 y1, uint16 x2, uint16 y2)
r <<= 1;
int16 t2 = x2 - x1;
-
if (t2 < 0) {
r++;
t2 = -t2;
}
- uint8 f = 1;
+ uint8 f = (t1 > t2) ? 1 : 0;
- if (t2 >= t1) {
- if (t2 > t1)
- f = 0;
+ if (t2 >= t1)
SWAP(t1, t2);
- }
r = (r << 1) | f;
@@ -281,8 +320,13 @@ void LoLEngine::setMonsterDirection(MonsterInPlay *monster, int dir) {
checkSceneUpdateNeed(monster->blockPropertyIndex);
}
-void LoLEngine::cmzS3(MonsterInPlay *l) {
- // TODO
+void LoLEngine::monsterDropItems(MonsterInPlay *monster) {
+ uint16 a = monster->assignedItems;
+ while (a) {
+ uint16 b = a;
+ a = _itemsInPlay[a].nextAssignedObject;
+ setItemPosition(b, monster->x, monster->y, 0, 1);
+ }
}
void LoLEngine::removeAssignedObjectFromBlock(LevelBlockProperty *l, int id) {
@@ -459,7 +503,7 @@ int LoLEngine::calcMonsterSkillLevel(int id, int a) {
int r = (a << 8) / c[4];
if (!(id & 0x8000))
- r = (r * _monsterModifiers[3 + ((_unkGameFlag & 0x30) << 4)]) >> 8;
+ r = (r * _monsterModifiers[3 + _monsterDifficulty]) >> 8;
id &= 0x7fff;
@@ -519,7 +563,6 @@ void LoLEngine::drawBlockObjects(int blockArrayIndex) {
if ((_itemProperties[i->itemPropertyIndex].flags & 0x1000) && !(i->shpCurFrame_flg & 0xC000)) {
int shpIndex = _itemProperties[i->itemPropertyIndex].flags & 0x800 ? 7 : _itemProperties[i->itemPropertyIndex].shpIndex;
- shpIndex=12;
int ii = 0;
for (; ii < 8; ii++) {
if (!_flyingItems[ii].enable)
@@ -612,7 +655,7 @@ void LoLEngine::drawMonster(uint16 id) {
int dW = _screen->getShapeScaledWidth(shp, _dmScaleW) >> 1;
int dH = _screen->getShapeScaledHeight(shp, _dmScaleH) >> 1;
- int a = (m->mode == 13) ? (m->field_15 << 1) : (m->properties->might / (m->field_1B & 0x7fff));
+ int a = (m->mode == 13) ? (m->fightCurTick << 1) : (m->properties->might / (m->field_1B & 0x7fff));
shp = _gameShapes[6];
@@ -654,7 +697,7 @@ int LoLEngine::getMonsterCurFrame(MonsterInPlay *m, uint16 dirFlags) {
switch (_monsterUnk[m->properties->shapeIndex]) {
case 0:
if (dirFlags) {
- return (*m->properties->pos & 0xff) == 13 ? -1 : (dirFlags + m->anon9);
+ return (m->properties->fightingStats[0] & 0xff) == 13 ? -1 : (dirFlags + m->currentSubFrame);
} else {
if (m->field_1B)
return 12;
@@ -663,13 +706,13 @@ int LoLEngine::getMonsterCurFrame(MonsterInPlay *m, uint16 dirFlags) {
case 0:
return m->field_1B ? 12 : ((m->properties->flags & 4) ? 13 : 0);
case 3:
- return (m->field_15 + 13);
+ return (m->fightCurTick + 13);
case 6:
return 14;
case 8:
return -1;
default:
- return m->field_1B ? 12 : m->anon9;
+ return m->field_1B ? 12 : m->currentSubFrame;
}
}
break;
@@ -738,8 +781,7 @@ void LoLEngine::redrawSceneItem() {
int t = (i << 7) + 1;
while (s) {
if (s & 0x8000) {
- s &= 0x7fff;
- s = _monsters[i].nextDrawObject;
+ s = _monsters[s & 0x7fff].nextDrawObject;
} else {
ItemInPlay *item = &_itemsInPlay[s];
@@ -769,7 +811,7 @@ int LoLEngine::calcItemMonsterPosition(ItemInPlay *i, uint16 direction) {
int x = i->x;
int y = i->y;
- recalcSpritePosition(_partyPosX, _partyPosY, x, y, direction);
+ calcSpriteRelPosition(_partyPosX, _partyPosY, x, y, direction);
if (y < 0)
y = 0;
@@ -780,9 +822,9 @@ int LoLEngine::calcItemMonsterPosition(ItemInPlay *i, uint16 direction) {
return res;
}
-void LoLEngine::recalcSpritePosition(uint16 partyX, uint16 partyY, int &itemX, int &itemY, uint16 direction) {
- int a = itemX - partyX;
- int b = partyY - itemY;
+void LoLEngine::calcSpriteRelPosition(uint16 x1, uint16 y1, int &x2, int &y2, uint16 direction) {
+ int a = x2 - x1;
+ int b = y1 - y2;
if (direction) {
if (direction != 2)
@@ -796,8 +838,8 @@ void LoLEngine::recalcSpritePosition(uint16 partyX, uint16 partyY, int &itemX, i
}
}
- itemX = a;
- itemY = b;
+ x2 = a;
+ y2 = b;
}
void LoLEngine::drawDoor(uint8 *shape, uint8 *table, int index, int unk2, int w, int h, int flags) {
@@ -938,7 +980,7 @@ uint8 *LoLEngine::drawItemOrMonster(uint8 *shape, uint8 *table, int x, int y, in
}
int LoLEngine::calcDrawingLayerParameters(int x1, int y1, int &x2, int &y2, uint16 &w, uint16 &h, uint8 *shape, int flip) {
- recalcSpritePosition(_partyPosX, _partyPosY, x1, y1, _currentDirection);
+ calcSpriteRelPosition(_partyPosX, _partyPosY, x1, y1, _currentDirection);
if (y1 < 0) {
w = h = x2 = y2 = 0;
@@ -965,10 +1007,10 @@ void LoLEngine::updateMonster(MonsterInPlay *monster) {
return;
int f = flags[monster->mode];
- if ((monster->tick++ < monster->properties->waitTicks) && (!(f & 4)))
+ if ((monster->speedTick++ < monster->properties->speedTotalWaitTicks) && (!(f & 4)))
return;
- monster->tick = 0;
+ monster->speedTick = 0;
if (monster->properties->flags & 0x40) {
monster->might += _rnd.getRandomNumberRng(1, 8);
@@ -982,11 +1024,12 @@ void LoLEngine::updateMonster(MonsterInPlay *monster) {
}
if (f & 2) {
-
- /////
- // TODO
+ if (updateMonsterAdjustBlocks(monster)) {
+ setMonsterMode(monster, 7);
+ f &= 6;
+ }
}
-
+
if ((f & 1) && (monster->flags & 0x10))
setMonsterMode(monster, 7);
@@ -1000,6 +1043,7 @@ void LoLEngine::updateMonster(MonsterInPlay *monster) {
switch (monster->mode) {
case 0:
case 1:
+ // friendly mode
if (monster->flags & 0x10) {
for (int i = 0; i < 30; i++) {
if (_monsters[i].mode == 1)
@@ -1009,28 +1053,87 @@ void LoLEngine::updateMonster(MonsterInPlay *monster) {
moveMonster(monster);
}
break;
+
case 2:
+ moveMonster(monster);
break;
- case 3:
+
+ case 3:
+ if (updateMonsterAdjustBlocks(monster))
+ setMonsterMode(monster, 7);
+ for (int i = 0; i < 4; i++) {
+ if (calcNewBlockPosition(monster->blockPropertyIndex, i) == _currentBlock)
+ setMonsterMode(monster, 7);
+ }
break;
+
case 4:
+ // straying around not tracing the party
+ moveStrayingMonster(monster);
break;
+
case 5:
+ // second recovery phase after delivering an attack
+ // monsters will rearrange positions in this phase so as to allow a maximum
+ // number of monsters possible attacking at the same time
+ _unkDrawLevelBool = true;
+ monster->fightCurTick--;
+ if ((monster->fightCurTick <= 0) || (checkDrawObjectSpace(_partyPosX, _partyPosY, monster->x, monster->y) > 256) || (monster->flags & 8))
+ setMonsterMode(monster, 7);
+ else
+ rearrangeAttackingMonster(monster);
break;
+
case 6:
+ // same as mode 5, but without rearranging
+ if (--monster->fightCurTick <= 0)
+ setMonsterMode(monster, 7);
break;
+
case 7:
+ // monster destination is set to current party position
+ // depending on the flag setting this gets updated each round
+ // monster can't change mode before arriving at destination and/or attacking the party
+ if (!chasePartyWithDistanceAttacks(monster))
+ chasePartyWithCloseAttacks(monster);
+ checkSceneUpdateNeed(monster->blockPropertyIndex);
break;
+
case 8:
+ // first recovery phase after delivering an attack
+ if (++monster->fightCurTick > 2) {
+ setMonsterMode(monster, 5);
+ monster->fightCurTick = (int8) ((((8 << 8) / monster->properties->fightingStats[4]) * _monsterModifiers[6 + _monsterDifficulty]) >> 8);
+ }
+ checkSceneUpdateNeed(monster->blockPropertyIndex);
break;
+
case 9:
+ if (--monster->fightCurTick) {
+ chasePartyWithCloseAttacks(monster);
+ } else {
+ setMonsterMode(monster, 7);
+ monster->flags &= 0xfff7;
+ }
+
break;
+
case 12:
+ checkSceneUpdateNeed(monster->blockPropertyIndex);
+ if (++monster->fightCurTick > 13)
+ runLevelScriptCustom(0x404, -1, monster->id, monster->id, 0, 0);
break;
+
case 13:
+ if (++monster->fightCurTick > 2)
+ mode13sub(monster);
+ checkSceneUpdateNeed(monster->blockPropertyIndex);
break;
+
case 14:
+ monster->field_1B = 0;
break;
+
default:
break;
}
@@ -1087,6 +1190,54 @@ void LoLEngine::walkMonster(MonsterInPlay *monster) {
placeMonster(monster, fx, fy);
}
+bool LoLEngine::chasePartyWithDistanceAttacks(MonsterInPlay *monster) {
+ if (!monster->field_25)
+ return false;
+
+ return true;
+}
+
+void LoLEngine::chasePartyWithCloseAttacks(MonsterInPlay *monster) {
+ if (!(monster->flags & 8)) {
+ int dir = calcMonsterDirection(monster->x & 0xff00, monster->y & 0xff00, _partyPosX & 0xff00, _partyPosY & 0xff00);
+ int x1 = _partyPosX;
+ int y1 = _partyPosY;
+
+ calcSpriteRelPosition(monster->x, monster->y, x1, y1, dir >> 1);
+
+ int t = (x1 < 0) ? -x1 : x1;
+ if (y1 <= 160 && t <= 80) {
+ if ((monster->direction == dir) && (monster->facing == (dir >> 1))) {
+ int dst = getClosestPartyMember(monster->x, monster->y);
+ snd_playSoundEffect(monster->properties->sounds[1], -1);
+ int m = monster->id | 0x8000;
+ int hit = battleHitSkillTest(m, dst, 0);
+
+ if (hit) {
+ int dmg = _rnd.getRandomNumberRng(2, calcInflictableDamage(m, dst, hit));
+ battleHit_sub2(dst, dmg, m, 0);
+ battleHit_sub3(monster, dst, dmg);
+ }
+
+ setMonsterMode(monster, 8);
+ checkSceneUpdateNeed(monster->blockPropertyIndex);
+
+ } else {
+ setMonsterDirection(monster, dir);
+ checkSceneUpdateNeed(monster->blockPropertyIndex);
+ }
+ return;
+ }
+ }
+
+ if (monster->x != monster->destX || monster->y != monster->destY) {
+ walkMonster(monster);
+ } else {
+ setMonsterDirection(monster, monster->destDirection);
+ setMonsterMode(monster, (_rnd.getRandomNumberRng(1, 100) <= 50) ? 4 : 3);
+ }
+}
+
int LoLEngine::walkMonsterCalcNextStep(MonsterInPlay *monster) {
static const int8 walkMonsterTable1[] = { 7, -6, 5, -4, 3, -2, 1, 0 };
static const int8 walkMonsterTable2[] = { -7, 6, -5, 4, -3, 2, -1, 0 };
@@ -1206,6 +1357,124 @@ void LoLEngine::getNextStepCoords(int16 srcX, int16 srcY, int &newX, int &newY,
newY = (srcY + shiftTableY[direction]) & 0x1fff;
}
+void LoLEngine::rearrangeAttackingMonster(MonsterInPlay *monster) {
+ int t = (monster->direction >> 1);
+ uint16 mx = monster->x;
+ uint16 my = monster->y;
+ uint16 *c = (t & 1) ? &my : &mx;
+ bool centered = (*c & 0x7f) ? false : true;
+
+ bool posFlag = true;
+ if (monster->properties->maxWidth <= 63) {
+ if (centered) {
+ bool r = false;
+
+ if (_levelBlockProperties[monster->blockPropertyIndex].assignedObjects & 0x8000) {
+ r = true;
+ } else {
+ uint16 id = _levelBlockProperties[monster->blockPropertyIndex].assignedObjects;
+ id = (id & 0x8000) ? (id & 0x7fff) : 0xffff;
+
+ if (id != monster->id) {
+ r = true;
+ } else {
+ for (int i = 0; i < 3; i++) {
+ t = (t + 1) & 3;
+ calcNewBlockPosition(monster->blockPropertyIndex, t);
+ id = _levelBlockProperties[monster->blockPropertyIndex].assignedObjects;
+ id = (id & 0x8000) ? (id & 0x7fff) : 0xffff;
+ if (id != 0xffff)
+ r = true;
+ }
+ }
+ }
+
+ if (r)
+ posFlag = false;
+ } else {
+ posFlag = false;
+ }
+ }
+
+ if (centered && posFlag)
+ return;
+
+ if (posFlag) {
+ if (*c & 0x80)
+ *c -= 32;
+ else
+ *c += 32;
+ } else {
+ if (*c & 0x80)
+ *c += 32;
+ else
+ *c -= 32;
+ }
+
+ if (walkMonsterCheckDest(mx, my, monster, 4))
+ return;
+
+ int fx = _partyPosX;
+ int fy = _partyPosY;
+ calcSpriteRelPosition(mx, my, fx, fy, monster->direction >> 1);
+
+ t = (fx < 0) ? -fx : fx;
+ if (fy > 160 || t > 80)
+ return;
+
+ placeMonster(monster, mx, my);
+}
+
+void LoLEngine::moveStrayingMonster(MonsterInPlay *monster) {
+ int x = 0;
+ int y = 0;
+
+ if (monster->fightCurTick) {
+ uint8 d = (monster->direction - monster->fightCurTick) & 6;
+ uint8 id = monster->id;
+
+ for (int i = 0; i < 7; i++) {
+ getNextStepCoords(monster->x, monster->y, x, y, d);
+
+ if (!walkMonsterCheckDest(x, y, monster, 4)) {
+ placeMonster(monster, x, y);
+ setMonsterDirection(monster, d);
+ if (!i) {
+ if (++id > 3)
+ monster->fightCurTick = 0;
+ }
+ return;
+ }
+
+ d = (d + monster->fightCurTick) & 6;
+ }
+ setMonsterMode(monster, 3);
+
+ } else {
+ monster->direction &= 6;
+ getNextStepCoords(monster->x, monster->y, x, y, monster->direction);
+ if (!walkMonsterCheckDest(x, y, monster, 4)) {
+ placeMonster(monster, x, y);
+ } else {
+ monster->fightCurTick = _rnd.getRandomBit() ? 2 : -2;
+ monster->direction = (monster->direction + monster->fightCurTick) & 6;
+ }
+ }
+}
+
+void LoLEngine::mode13sub(MonsterInPlay *monster) {
+ setMonsterMode(monster, 14);
+ monsterDropItems(monster);
+ checkSceneUpdateNeed(monster->blockPropertyIndex);
+
+ uint8 w = _levelBlockProperties[monster->blockPropertyIndex].walls[0];
+ uint8 f = _levelBlockProperties[monster->blockPropertyIndex].flags;
+ if (_wllVmpMap[w] == 0 && _wllShapeMap[w] == 0 && !(f & 0x40) && !(monster->properties->flags & 0x1000))
+ _levelBlockProperties[monster->blockPropertyIndex].flags |= 0x80;
+
+ placeMonster(monster, 0, 0);
+}
+
} // end of namespace Kyra
#endif // ENABLE_LOL