KYRA: (EOB/SegaCD) - fix decorations and monster animations

This commit is contained in:
athrxx 2020-03-24 22:08:46 +01:00
parent 5da41b3e11
commit b59d201873
9 changed files with 120 additions and 84 deletions

View File

@ -56,6 +56,7 @@ EoBEngine::EoBEngine(OSystem *system, const GameFlags &flags)
_seqPlayer = 0;
_sres = 0;
_levelCurTrack = 0;
_dcrResCur = -1;
}
EoBEngine::~EoBEngine() {
@ -448,7 +449,7 @@ void EoBEngine::loadMonsterShapes(const char *filename, int monsterIndex, bool h
assert(size <= 18);
for (int i = 0; i < size; i++) {
_monsterShapes[monsterIndex + i] = _screen->sega_encodeShape(pos, enc[0], enc[1], 2);
_monsterShapes[monsterIndex + i] = _screen->sega_convertShape(pos, enc[0], enc[1], 2);
pos += ((enc[0] * enc[1]) >> 1);
enc += 2;
}
@ -563,6 +564,7 @@ const uint8 *EoBEngine::getBlockFileData(int level) {
Common::SeekableReadStream *s = _sres->resStream(6);
_screen->loadFileDataToPage(s, 15, s->size());
delete s;
_dcrResCur = -1;
return _screen->getCPagePtr(15);
}
@ -574,13 +576,18 @@ Common::SeekableReadStreamEndian *EoBEngine::getDecDefinitions(const char *decFi
}
void EoBEngine::loadDecShapesToPage3(const char *shpFile) {
if (_flags.platform != Common::kPlatformSegaCD)
return EoBCoreEngine::loadDecShapesToPage3(shpFile);
_sres->loadContainer(Common::String::format("L%d", _currentLevel));
Common::SeekableReadStream *s = _sres->resStream(2);
_screen->loadFileDataToPage(s, 3, s->size());
_dcrShpDataPos = _screen->getCPagePtr(3);
delete s;
if (_flags.platform != Common::kPlatformSegaCD) {
EoBCoreEngine::loadDecShapesToPage3(shpFile);
return;
}
if (_dcrResCur != _currentLevel) {
_sres->loadContainer(Common::String::format("L%d", _currentLevel));
Common::SeekableReadStream *s = _sres->resStream(2);
_screen->loadFileDataToPage(s, 3, s->size());
_dcrShpDataPos = _screen->getCPagePtr(3);
_dcrResCur = _currentLevel;
delete s;
}
}
void EoBEngine::loadDoorShapes(int doorType1, int shapeId1, int doorType2, int shapeId2) {
@ -606,9 +613,9 @@ void EoBEngine::loadDoorShapes(int doorType1, int shapeId1, int doorType2, int s
if (_flags.platform == Common::kPlatformSegaCD) {
int offs = lvlIndex[_currentLevel] * 6 + shapeId[a] + i;
const uint8 *enc = &_doorShapeEncodeDefs[offs << 2];
_doorShapes[shapeId[a] + i] = _screen->sega_encodeShape(_doorShapesSrc[offs], enc[0] << 3, enc[1] << 3, 0);
_doorShapes[shapeId[a] + i] = _screen->sega_convertShape(_doorShapesSrc[offs], enc[0] << 3, enc[1] << 3, 0);
enc = &_doorSwitchShapeEncodeDefs[(offs << 2) - shapeId[a]];
_doorSwitches[shapeId[a] + i].shp = _screen->sega_encodeShape(_doorSwitchShapesSrc[offs], enc[0] << 3, enc[1] << 3, 0);
_doorSwitches[shapeId[a] + i].shp = _screen->sega_convertShape(_doorSwitchShapesSrc[offs], enc[0] << 3, enc[1] << 3, 0);
} else {
const uint8 *enc = &_doorShapeEncodeDefs[(doorType[a] * 3 + i) << 2];
_doorShapes[shapeId[a] + i] = _screen->encodeShape(enc[0], enc[1], enc[2], enc[3], false, _cgaLevelMappingIndex ? _cgaMappingLevel[_cgaLevelMappingIndex[_currentLevel - 1]] : 0);

View File

@ -155,6 +155,8 @@ private:
const uint8 *const *_doorShapesSrc;
const uint8 *const *_doorSwitchShapesSrc;
int _dcrResCur;
// Fight
static const uint8 _monsterAcHitChanceTbl1[];
static const uint8 _monsterAcHitChanceTbl2[];

View File

@ -56,8 +56,10 @@ EoBCoreEngine::EoBCoreEngine(OSystem *system, const GameFlags &flags) : KyraRpgE
_enableHiResDithering = false;
_tickLength = 55;
_envAudioTimer = 0;
_flashShapeTimer = 0;
_flashShapeTimerIntv = (_flags.platform == Common::kPlatformSegaCD ? 16 : _tickLength) * 8;
_drawSceneTimer = 0;
_vcnFilePattern = "%s.VCN";
_vmpFilePattern = "%s.VMP";
@ -372,10 +374,6 @@ Common::KeymapArray EoBCoreEngine::initKeymaps(const Common::String &gameId) {
}
Common::Error EoBCoreEngine::init() {
// In EOB the timer proc is directly invoked via interrupt 0x1C, 18.2 times per second.
// This makes a tick length of 54.94.
_tickLength = 55;
if (ConfMan.hasKey("render_mode"))
_configRenderMode = Common::parseRenderMode(ConfMan.get("render_mode"));

View File

@ -202,6 +202,8 @@ struct EoBMonsterInPlay {
int8 mode;
int8 stray;
int8 curAttackFrame;
uint8 animProgress;
uint8 animType;
int8 spellStatusLeft;
int16 hitPointsMax;
int16 hitPointsCur;
@ -646,6 +648,7 @@ protected:
uint32 _drawSceneTimer;
uint32 _flashShapeTimer;
uint32 _flashShapeTimerIntv;
uint32 _envAudioTimer;
uint16 _teleporterPulse;

View File

@ -490,7 +490,7 @@ void EoBCoreEngine::assignWallsAndDecorations(int wallIndex, int vmpIndex, int d
error("Error trying to make decoration %d (x: %d, y: %d, w: %d, h: %d)", decIndex, r->x, r->y, r->w, r->h);
if (_flags.platform == Common::kPlatformSegaCD) {
_levelDecorationShapes[t] = _screen->sega_encodeShape(_dcrShpDataPos, r->w << 3, r->h, 0);
_levelDecorationShapes[t] = _screen->sega_convertShape(_dcrShpDataPos, r->w << 3, r->h, 0);
_dcrShpDataPos += ((r->w << 2) * r->h);
} else {
_levelDecorationShapes[t] = _screen->encodeShape(r->x, r->y, r->w, r->h, false, _cgaLevelMappingIndex ? _cgaMappingLevel[_cgaLevelMappingIndex[_currentLevel - 1]] : 0);
@ -582,7 +582,7 @@ void EoBCoreEngine::drawScene(int refresh) {
_screen->updateScreen();
if (_sceneDefaultUpdate) {
_sceneDefaultUpdate = false;
_sceneDefaultUpdate = 0;
_drawSceneTimer = _system->getMillis() + 4 * _tickLength;
}

View File

@ -61,8 +61,13 @@ void EoBCoreEngine::releaseMonsterShapes(int first, int num) {
}
const uint8 *EoBCoreEngine::loadActiveMonsterData(const uint8 *data, int level) {
static const uint8 intervals[4] = { 35, 30, 25, 0 };
for (uint8 p = *data++; p != 0xFF; p = *data++) {
uint8 v = *data++;
if (_flags.platform == Common::kPlatformSegaCD) {
assert(v < ARRAYSIZE(intervals));
v = intervals[v];
}
_timer->setCountdown(0x20 + (p << 1), v);
_timer->setCountdown(0x21 + (p << 1), v);
}
@ -459,75 +464,91 @@ void EoBCoreEngine::drawMonsters(int index) {
int subFrame = ABS(f);
int shpIndex = d->shpIndex ? 18 : 0;
int palIndex = d->palette ? ((((shpIndex == 18) ? subFrame + 5 : subFrame - 1) << 1) + (d->palette - 1)) : -1;
if (_flags.platform == Common::kPlatformSegaCD) {
if (d->curAttackFrame == -1)
subFrame = 5;
else if (f == 3)
subFrame = 2;
else if (f == -3)
subFrame = 4;
else if (f == 4)
subFrame = 3;
else if (f == -4)
subFrame = -3;
}
const uint8 *shp = _screen->scaleShape(_monsterShapes[subFrame + shpIndex - 1], blockDistance);
int shpOffs = subFrame + shpIndex - 1;
int xAdd2 = 0;
int yAdd2 = 0;
int v30 = (subFrame == 1 || subFrame > 3) ? 1 : 0;
int v1e = (d->pos == 4) ? 4 : _dscItemPosIndex[cDirOffs + d->pos];
int posIndex = (index * 5 + v1e) << 1;
int posOffs = (d->pos == 4) ? 4 : _dscItemPosIndex[cDirOffs + d->pos];
int posIndex = (index * 5 + posOffs) << 1;
int x = _dscShapeCoords[posIndex] + 88;
int y = _dscShapeCoords[posIndex + 1] + 127;
if (_flags.platform == Common::kPlatformSegaCD) {
if (d->curAttackFrame < 0)
subFrame = 5;
else if (subFrame >= 3)
subFrame--;
if (p->u30 == 1) {
if (v30) {
if (_flags.gameID == GI_EOB2)
posIndex = ((posIndex >> 1) - v1e) << 1;
y = _dscShapeCoords[posIndex + 1] + 127 + yAdd[blockDistance + ((v1e == 4 || _flags.gameID == GI_EOB1) ? 0 : 3)];
} else {
if (_flags.gameID == GI_EOB2)
posIndex = ((posIndex >> 1) - v1e + 4) << 1;
x = _dscShapeCoords[posIndex] + 88;
if (d->animType != subFrame) {
d->animType = subFrame;
d->animProgress = 0;
}
} else if (d->curAttackFrame < 0) {
d->curAttackFrame++;
}
int w = shp[2] << 3;
int h = shp[1];
for (int numFrames = 1; numFrames; --numFrames) {
if (_flags.platform == Common::kPlatformSegaCD) {
int temp = 0;
const uint8 *frm = _staticres->loadRawData(kEoB1MonsterAnimFrames00 + d->type * 5 + subFrame - 1, temp) + ((d->animProgress++) << 2);
shpOffs = shpIndex + (frm[0] & 0x3F);
numFrames += ((frm[0] >> 6) & 1);
xAdd2 = (int8)frm[1];
yAdd2 = (int8)frm[2];
if (frm[4] == 0xFE)
d->animProgress = 0;
else if (frm[4] == 0xFF)
d->curAttackFrame = 0;
}
x = x - (w >> 1) + (d->idleAnimState >> 4);
y = y - h + (d->idleAnimState & 0x0F);
const uint8 *shp = _screen->scaleShape(_monsterShapes[shpOffs], blockDistance);
drawMonsterShape(shp, x, y, f >= 0 ? 0 : 1, d->flags, palIndex);
int x = _dscShapeCoords[posIndex] + 88;
int y = _dscShapeCoords[posIndex + 1] + 127;
if (_flags.gameID == GI_EOB1) {
if (p->u30 == 1) {
if (v30) {
if (_flags.gameID == GI_EOB2)
posIndex = ((posIndex >> 1) - posOffs) << 1;
y = _dscShapeCoords[posIndex + 1] + 127 + yAdd[blockDistance + ((posOffs == 4 || _flags.gameID == GI_EOB1) ? 0 : 3)];
} else {
if (_flags.gameID == GI_EOB2)
posIndex = ((posIndex >> 1) - posOffs + 4) << 1;
x = _dscShapeCoords[posIndex] + 88;
}
}
int w = shp[2] << 3;
int h = shp[1];
x = x - (w >> 1) + (d->idleAnimState >> 4) + xAdd2;
y = y - h + (d->idleAnimState & 0x0F) + yAdd2;
drawMonsterShape(shp, x, y, f >= 0 ? 0 : 1, d->flags, palIndex);
if (_flags.gameID == GI_EOB2) {
for (int ii = 0; ii < 3; ii++) {
if (!p->decorations[ii])
continue;
SpriteDecoration *dcr = &_monsterDecorations[(p->decorations[ii] - 1) * 6 + subFrame + shpIndex - 1];
if (!dcr->shp)
continue;
shp = _screen->scaleShape(dcr->shp, blockDistance);
int dx = dcr->x;
int dy = dcr->y;
for (int iii = 0; iii < blockDistance; iii++) {
dx = (dx << 1) / 3;
dy = (dy << 1) / 3;
}
drawMonsterShape(shp, x + ((f < 0) ? (w - dx - (shp[2] << 3)) : dx), y + dy, f >= 0 ? 0 : 1, d->flags, -1);
}
}
_screen->setShapeFadingLevel(0);
continue;
}
for (int ii = 0; ii < 3; ii++) {
if (!p->decorations[ii])
continue;
SpriteDecoration *dcr = &_monsterDecorations[(p->decorations[ii] - 1) * 6 + subFrame + shpIndex - 1];
if (!dcr->shp)
continue;
shp = _screen->scaleShape(dcr->shp, blockDistance);
int dx = dcr->x;
int dy = dcr->y;
for (int iii = 0; iii < blockDistance; iii++) {
dx = (dx << 1) / 3;
dy = (dy << 1) / 3;
}
drawMonsterShape(shp, x + ((f < 0) ? (w - dx - (shp[2] << 3)) : dx), y + dy, f >= 0 ? 0 : 1, d->flags, -1);
}
_screen->setShapeFadingLevel(0);
}
}
@ -1009,16 +1030,19 @@ bool EoBCoreEngine::updateMonsterTryCloseAttack(EoBMonsterInPlay *m, int block)
if (facing) {
disableSysTimer(2);
if (m->type == 4)
if ((_flags.platform == Common::kPlatformSegaCD) == (m->type != 4))
snd_updateEnvironmentalSfx(_monsterProps[m->type].sound1);
m->curAttackFrame = -2;
_flashShapeTimer = 0;
drawScene(1);
m->curAttackFrame = -1;
if (m->type != 4)
snd_updateEnvironmentalSfx(_monsterProps[m->type].sound1);
_flashShapeTimer = _system->getMillis() + 8 * _tickLength;
drawScene(1);
m->curAttackFrame = -2;
for (int i = 0; i < 16 && m->curAttackFrame < 0; ++i) {
if (m->type != 4 && m->curAttackFrame == -1)
snd_updateEnvironmentalSfx(_monsterProps[m->type].sound1);
drawScene(1);
_flashShapeTimer = _system->getMillis() + _flashShapeTimerIntv;
}
} else {
snd_updateEnvironmentalSfx(_monsterProps[m->type].sound1);
}
@ -1030,7 +1054,7 @@ bool EoBCoreEngine::updateMonsterTryCloseAttack(EoBMonsterInPlay *m, int block)
m->animStep ^= 1;
_sceneUpdateRequired = 1;
enableSysTimer(2);
_flashShapeTimer = _system->getMillis() + 8 * _tickLength;
_flashShapeTimer = _system->getMillis() + _flashShapeTimerIntv;
}
} else {
int b = m->block;

View File

@ -132,7 +132,7 @@ public:
void sega_loadTextBufferToVRAM(uint16 srcOffset, uint16 addr, int size);
void sega_gfxScale(uint8 *out, uint16 w, uint16 h, uint16 pitch, const uint8 *in, const uint16 *stampMap, const uint16 *traceVectors);
void sega_drawClippedLine(uint8 *dst, int pW, int pH, int x, int y, int w, int h, uint8 color);
uint8 *sega_encodeShape(const uint8 *src, int w, int h, int pal);
uint8 *sega_convertShape(const uint8 *src, int w, int h, int pal);
void sega_encodeShapesFromSprites(const uint8 **dst, const uint8 *src, int numShapes, int w, int h, int pal);
SegaRenderer *sega_getRenderer() const { return _segaRenderer; }

View File

@ -289,7 +289,7 @@ void Screen_EoB::sega_drawClippedLine(uint8 *dst, int pW, int pH, int x, int y,
}
}
uint8 *Screen_EoB::sega_encodeShape(const uint8 *src, int w, int h, int pal) {
uint8 *Screen_EoB::sega_convertShape(const uint8 *src, int w, int h, int pal) {
uint8 *shp = new uint8[(w >> 1) * h + 20];
uint8 *dst = shp;
*dst++ = 2;

View File

@ -249,6 +249,8 @@ Common::Error EoBCoreEngine::loadGameState(int slot) {
m->directionChanged = in.readByte();
m->stepsTillRemoteAttack = in.readByte();
m->sub = in.readByte();
m->animType = 0;
m->animProgress = 0;
}
for (int ii = 0; ii < _numFlyingObjects; ii++) {