aboutsummaryrefslogtreecommitdiff
path: root/engines/kyra/lol.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'engines/kyra/lol.cpp')
-rw-r--r--engines/kyra/lol.cpp891
1 files changed, 805 insertions, 86 deletions
diff --git a/engines/kyra/lol.cpp b/engines/kyra/lol.cpp
index 9093c63dc9..a05003ffbd 100644
--- a/engines/kyra/lol.cpp
+++ b/engines/kyra/lol.cpp
@@ -63,6 +63,9 @@ LoLEngine::LoLEngine(OSystem *system, const GameFlags &flags) : KyraEngine_v1(sy
_lang = 2;
break;
+ case Common::JA_JPN:
+ _lang = 0;
+
default:
warning("unsupported language, switching back to English");
_lang = 0;
@@ -91,13 +94,14 @@ LoLEngine::LoLEngine(OSystem *system, const GameFlags &flags) : KyraEngine_v1(sy
_specialSceneFlag = 0;
_lastCharInventory = -1;
- _itemIconShapes = _itemShapes = _gameShapes = _thrownShapes = _effectShapes = _fireballShapes = 0;
+ _itemIconShapes = _itemShapes = _gameShapes = _thrownShapes = _effectShapes = _fireballShapes = _healShapes = _healiShapes = 0;
_levelShpList = _levelDatList = 0;
_monsterShapes = _monsterPalettes = 0;
_monsterShapesEx = 0;
_gameShapeMap = 0;
memset(_monsterUnk, 0, 3);
_pageSavedFlag = false;
+ _healOverlay = 0;
_ingameMT32SoundIndex = _ingameGMSoundIndex = /*_ingameADLSoundIndex =*/ 0;
@@ -181,7 +185,11 @@ LoLEngine::LoLEngine(OSystem *system, const GameFlags &flags) : KyraEngine_v1(sy
_curMusicTheme = -1;
_curMusicFileExt = 0;
_curMusicFileIndex = -1;
- _environmentSfx = _environmentSfxVol = _environmentSfxDistThreshold = 0;
+ _environmentSfx = _environmentSfxVol = _envSfxDistThreshold = 0;
+ _envSfxUseQueue = false;
+ _envSfxNumTracksInQueue = 0;
+ memset (_envSfxQueuedTracks, 0, sizeof(_envSfxQueuedTracks));
+ memset (_envSfxQueuedBlocks, 0, sizeof(_envSfxQueuedBlocks));
_sceneDrawVarDown = _sceneDrawVarRight = _sceneDrawVarLeft = _wllProcessFlag = 0;
_partyPosX = _partyPosY = 0;
@@ -198,7 +206,7 @@ LoLEngine::LoLEngine(OSystem *system, const GameFlags &flags) : KyraEngine_v1(sy
memset(_charStatsTemp, 0, sizeof(_charStatsTemp));
- _compassBroken = _unkBt2 = 0;
+ _compassBroken = _drainMagic = 0;
_dialogueField = false;
_rndSpecial = 0x12349876;
@@ -220,6 +228,8 @@ LoLEngine::LoLEngine(OSystem *system, const GameFlags &flags) : KyraEngine_v1(sy
_defaultLegendData = 0;
_compassTimer = 0;
+ _timer3Para = 0;
+ _partyDeathFlag = -1;
}
LoLEngine::~LoLEngine() {
@@ -250,32 +260,49 @@ LoLEngine::~LoLEngine() {
delete[] _itemIconShapes[i];
delete[] _itemIconShapes;
}
+
if (_itemShapes) {
for (int i = 0; i < _numItemShapes; i++)
delete[] _itemShapes[i];
delete[] _itemShapes;
}
+
if (_gameShapes) {
for (int i = 0; i < _numGameShapes; i++)
delete[] _gameShapes[i];
delete[] _gameShapes;
}
+
if (_thrownShapes) {
for (int i = 0; i < _numThrownShapes; i++)
delete[] _thrownShapes[i];
delete[] _thrownShapes;
}
+
if (_effectShapes) {
for (int i = 0; i < _numEffectShapes; i++)
delete[] _effectShapes[i];
delete[] _effectShapes;
}
+
if (_fireballShapes) {
for (int i = 0; i < _numFireballShapes; i++)
delete[] _fireballShapes[i];
delete[] _fireballShapes;
}
+ if (_healShapes) {
+ for (int i = 0; i < _numHealShapes; i++)
+ delete[] _healShapes[i];
+ delete[] _healShapes;
+ }
+
+ if (_healiShapes) {
+ for (int i = 0; i < _numHealiShapes; i++)
+ delete[] _healiShapes[i];
+ delete[] _healiShapes;
+ }
+
if (_monsterShapes) {
for (int i = 0; i < 48; i++)
delete[] _monsterShapes[i];
@@ -357,6 +384,8 @@ LoLEngine::~LoLEngine() {
}
}
+ delete[] _healOverlay;
+
delete[] _defaultLegendData;
delete[] _mapCursorOverlay;
delete[] _mapOverlay;
@@ -378,7 +407,7 @@ Common::Error LoLEngine::init() {
KyraEngine_v1::init();
initStaticResource();
- _environmentSfxDistThreshold = (MidiDriver::detectMusicDriver(MDT_MIDI | MDT_ADLIB) == MD_ADLIB || ConfMan.getBool("multi_midi")) ? 15 : 3;
+ _envSfxDistThreshold = (MidiDriver::detectMusicDriver(MDT_MIDI | MDT_ADLIB) == MD_ADLIB || ConfMan.getBool("multi_midi")) ? 15 : 3;
_gui = new GUI_LoL(this);
assert(_gui);
@@ -475,6 +504,7 @@ Common::Error LoLEngine::init() {
Common::Error LoLEngine::go() {
setupPrologueData(true);
+ _sound->setSoundList(&_soundData[kMusicIntro]);
if (!saveFileLoadable(0))
showIntro();
@@ -532,7 +562,7 @@ Common::Error LoLEngine::go() {
return Common::kNoError;
if (processSelection == 0) {
- _sound->loadSoundFile("LOREINTR");
+ _sound->loadSoundFile(0);
_sound->playTrack(6);
chooseCharacter();
_sound->playTrack(1);
@@ -541,6 +571,9 @@ Common::Error LoLEngine::go() {
setupPrologueData(false);
+ _sound->setSoundList(&_soundData[kMusicIngame]);
+ _sound->loadSoundFile(0);
+
_tim = new TIMInterpreter_LoL(this, _screen, _system);
assert(_tim);
@@ -637,15 +670,27 @@ int LoLEngine::mainMenu() {
bool hasSave = saveFileLoadable(0);
- MainMenu::StaticData data = {
- { 0, 0, 0, 0, 0 },
- { 0x01, 0x04, 0x0C, 0x04, 0x00, 0x3D, 0x9F },
- { 0x2C, 0x19, 0x48, 0x2C },
- Screen::FID_9_FNT, 1
+ MainMenu::StaticData data[] = {
+ // 256 color mode
+ {
+ { 0, 0, 0, 0, 0 },
+ { 0x01, 0x04, 0x0C, 0x04, 0x00, 0x3D, 0x9F },
+ { 0x2C, 0x19, 0x48, 0x2C },
+ Screen::FID_9_FNT, 1
+ },
+ // 16 color mode
+ {
+ { 0, 0, 0, 0, 0 },
+ { 0x01, 0x04, 0x0C, 0x03, 0x00, 0xC1, 0xE1 },
+ { 0xCC, 0xDD, 0xDD, 0xDD },
+ Screen::FID_9_FNT, 1
+ }
};
+ int dataIndex = _flags.use16ColorMode ? 1 : 0;
+
if (hasSave)
- ++data.menuTable[3];
+ ++data[dataIndex].menuTable[3];
static const uint16 mainMenuStrings[4][5] = {
{ 0x4248, 0x4249, 0x42DD, 0x424A, 0x0000 },
@@ -658,14 +703,14 @@ int LoLEngine::mainMenu() {
for (int i = 0; i < 5; ++i) {
if (hasSave)
- data.strings[i] = getLangString(mainMenuStrings[1 + tableOffs][i]);
+ data[dataIndex].strings[i] = getLangString(mainMenuStrings[1 + tableOffs][i]);
else
- data.strings[i] = getLangString(mainMenuStrings[tableOffs][i]);
+ data[dataIndex].strings[i] = getLangString(mainMenuStrings[tableOffs][i]);
}
MainMenu *menu = new MainMenu(this);
assert(menu);
- menu->init(data, MainMenu::Animation());
+ menu->init(data[dataIndex], MainMenu::Animation());
int selection = menu->handle(_flags.isTalkie ? (hasSave ? 12 : 6) : (hasSave ? 6 : 13));
delete menu;
@@ -735,6 +780,20 @@ void LoLEngine::startup() {
for (int i = 0; i < _numFireballShapes; i++)
_fireballShapes[i] = _screen->makeShapeCopy(shp, i);
+ _screen->loadBitmap("HEAL.SHP", 3, 3, 0);
+ shp = _screen->getCPagePtr(3);
+ _numHealShapes = READ_LE_UINT16(shp);
+ _healShapes = new uint8*[_numHealShapes];
+ for (int i = 0; i < _numHealShapes; i++)
+ _healShapes[i] = _screen->makeShapeCopy(shp, i);
+
+ _screen->loadBitmap("HEALI.SHP", 3, 3, 0);
+ shp = _screen->getCPagePtr(3);
+ _numHealiShapes = READ_LE_UINT16(shp);
+ _healiShapes = new uint8*[_numHealiShapes];
+ for (int i = 0; i < _numHealiShapes; i++)
+ _healiShapes[i] = _screen->makeShapeCopy(shp, i);
+
memset(_itemsInPlay, 0, 400 * sizeof(ItemInPlay));
for (int i = 0; i < 400; i++)
_itemsInPlay[i].shpCurFrame_flg |= 0x8000;
@@ -814,10 +873,10 @@ void LoLEngine::runLoop() {
else
updateEnvironmentalSfx(0);
- /*if (_partyDeathFlag != -1) {
- checkForPartyDeath(_partyDeathFlag);
+ if (_partyDeathFlag != -1) {
+ checkForPartyDeath();
_partyDeathFlag = -1;
- }*/
+ }
delay(_tickLength);
}
@@ -864,8 +923,12 @@ char *LoLEngine::getLangString(uint16 id) {
char *string = (char *)getTableEntry(buffer, realId);
char *srcBuffer = _stringBuffer[_lastUsedStringBuffer];
- Util::decodeString1(string, srcBuffer);
- Util::decodeString2(srcBuffer, srcBuffer);
+ if (_flags.lang != Common::JA_JPN) {
+ Util::decodeString1(string, srcBuffer);
+ Util::decodeString2(srcBuffer, srcBuffer);
+ } else {
+ decodeSjis(string, srcBuffer);
+ }
++_lastUsedStringBuffer;
_lastUsedStringBuffer %= ARRAYSIZE(_stringBuffer);
@@ -881,6 +944,36 @@ uint8 *LoLEngine::getTableEntry(uint8 *buffer, uint16 id) {
return buffer + READ_LE_UINT16(buffer + (id<<1));
}
+void LoLEngine::decodeSjis(const char *src, char *dst) {
+ char s[2];
+ char d[3];
+ s[1] = 0;
+
+ uint8 cmd = *src++;
+
+ while (cmd) {
+ if (cmd == 27) {
+ cmd = *src & 0x7f;
+ src++;
+
+ for (int i = 0; i < cmd; i ++) {
+ *dst++ = *src++;
+ *dst++ = *src++;
+ }
+ cmd = *src++;
+
+ } else {
+ s[0] = *src++;
+ Util::decodeString1(s, d);
+ *dst++ = d[0];
+ cmd = *src++;
+ }
+ }
+
+ if (!cmd)
+ *dst = 0;
+}
+
bool LoLEngine::addCharacter(int id) {
const uint16 *cdf[] = { _charDefsMan, _charDefsMan, _charDefsMan, _charDefsWoman,
_charDefsMan, _charDefsMan, _charDefsWoman, _charDefsKieran, _charDefsAkshel };
@@ -913,29 +1006,30 @@ bool LoLEngine::addCharacter(int id) {
calcCharPortraitXpos();
if (numChars > 0)
- setFaceFrames(numChars, 2, 6, 0);
+ setTemporaryFaceFrame(numChars, 2, 6, 0);
return true;
}
-void LoLEngine::setFaceFrames(int charNum, int defaultFrame, int unk2, int redraw) {
- _characters[charNum].defaultFaceFrame = defaultFrame;
- if (defaultFrame || unk2)
- setFaceFramesUnkArrays(charNum, 6, unk2, 1);
+void LoLEngine::setTemporaryFaceFrame(int charNum, int frame, int updateDelay, int redraw) {
+ _characters[charNum].defaultFaceFrame = frame;
+ if (frame || updateDelay)
+ setCharacterUpdateEvent(charNum, 6, updateDelay, 1);
if (redraw)
gui_drawCharPortraitWithStats(charNum);
}
-void LoLEngine::setFaceFramesUnkArrays(int charNum, int unk1, int unk2, int unk3) {
+void LoLEngine::setCharacterUpdateEvent(int charNum, int updateType, int updateDelay, int overwrite) {
LoLCharacter *l = &_characters[charNum];
for (int i = 0; i < 5; i++) {
- if (l->arrayUnk2[i] && (!unk3 || l->arrayUnk2[i] != unk1))
+ if (l->characterUpdateEvents[i] && (!overwrite || l->characterUpdateEvents[i] != updateType))
continue;
- l->arrayUnk2[i] = unk1;
- l->arrayUnk1[i] = unk2;
+ l->characterUpdateEvents[i] = updateType;
+ l->characterUpdateDelay[i] = updateDelay;
_timer->setNextRun(3, _system->getMillis());
_timer->enable(3);
+ break;
}
}
@@ -1057,10 +1151,10 @@ void LoLEngine::setCharFaceFrame(int charNum, int frameNum) {
void LoLEngine::faceFrameRefresh(int charNum) {
if (_characters[charNum].curFaceFrame == 1)
- setFaceFrames(charNum, 0, 0, 0);
+ setTemporaryFaceFrame(charNum, 0, 0, 0);
else if (_characters[charNum].curFaceFrame == 6)
if (_characters[charNum].defaultFaceFrame != 5)
- setFaceFrames(charNum, 0, 0, 0);
+ setTemporaryFaceFrame(charNum, 0, 0, 0);
else
_characters[charNum].curFaceFrame = 5;
else
@@ -1114,7 +1208,7 @@ int LoLEngine::calculateProtection(int index) {
c = (_monsters[index].properties->itemProtection * _monsters[index].properties->fightingStats[2]) >> 8;
} else {
// Character
- c = _characters[index].itemsProtection + _characters[index].protection;
+ c = _characters[index].itemProtection + _characters[index].protection;
c = (c * _characters[index].defaultModifiers[2]) >> 8;
c = (c * _characters[index].totalProtectionModifier) >> 8;
}
@@ -1122,6 +1216,74 @@ int LoLEngine::calculateProtection(int index) {
return c;
}
+void LoLEngine::setCharacterMagicOrHitPoints(int charNum, int type, int points, int mode) {
+ static const uint16 barData[2][5] = {
+ // xPos, bar color, text color, flag, string id
+ { 0x27, 0x9A, 0x98, 0x01, 0x4254 },
+ { 0x21, 0xA2, 0xA0, 0x00, 0x4253 }
+ };
+
+ LoLCharacter *c = &_characters[charNum];
+ if (!(c->flags & 1))
+ return;
+
+ int pointsMax = type ? c->magicPointsMax : c->hitPointsMax;
+ int pointsCur = type ? c->magicPointsCur : c->hitPointsCur;
+
+ int newVal = (mode == 2) ? (pointsMax + points) : (mode ? (pointsCur + points) : points);
+ newVal = CLIP(newVal, 0, pointsMax);
+
+ if (type) {
+ c->magicPointsCur = newVal;
+ } else {
+ c->hitPointsCur = newVal;
+ if (c->hitPointsCur < 1)
+ c->flags |= 8;
+ }
+
+ if (_updateFlags & 2)
+ return;
+
+ Screen::FontId cf = _screen->setFont(Screen::FID_6_FNT);
+ int cp = _screen->setCurPage(0);
+
+ int s = 8192 / pointsMax;
+ pointsMax = (s * pointsMax) >> 8;
+ pointsCur = (s * pointsCur) >> 8;
+ newVal = (s * newVal) >> 8;
+ int newValScl = CLIP(newVal, 0, pointsMax);
+
+ int step = (newVal > pointsCur) ? 2 : -2;
+ newVal = CLIP(newVal + step, 0, pointsMax);
+
+ if (newVal != pointsCur) {
+ step = (newVal >= pointsCur) ? 2 : -2;
+
+ for (int i = pointsCur; i != newVal || newVal != newValScl;) {
+ if (ABS(i - newVal) < ABS(step))
+ step >>= 1;
+
+ i += step;
+
+ _smoothScrollTimer = _system->getMillis() + _tickLength;
+
+ gui_drawLiveMagicBar(barData[type][0] + _activeCharsXpos[charNum], 175, i, 0, pointsMax, 5, 32, barData[type][1], 1, barData[type][3]);
+ _screen->printText(getLangString(barData[type][4]), barData[type][0] + _activeCharsXpos[charNum], 144, barData[type][2], 0);
+ _screen->updateScreen();
+
+ if (i == newVal) {
+ newVal = newValScl;
+ step = -step;
+ }
+
+ delayUntil(_smoothScrollTimer);
+ }
+ }
+
+ _screen->setFont(cf);
+ _screen->setCurPage(cp);
+}
+
void LoLEngine::increaseExperience(int charNum, int skill, uint32 points) {
if (charNum & 0x8000)
return;
@@ -1174,6 +1336,17 @@ void LoLEngine::increaseExperience(int charNum, int skill, uint32 points) {
}
}
+void LoLEngine::increaseCharacterHitpoints(int charNum, int points, bool ignoreDeath) {
+ if (_characters[charNum].hitPointsCur <= 0 && !ignoreDeath)
+ return;
+
+ if (points <= 1)
+ points = 1;
+
+ _characters[charNum].hitPointsCur = CLIP<int16>(_characters[charNum].hitPointsCur + points, 1, _characters[charNum].hitPointsMax);
+ _characters[charNum].flags &= 0xfff7;
+}
+
void LoLEngine::setupScreenDims() {
if (textEnabled()) {
_screen->modifyScreenDim(4, 11, 124, 28, 45);
@@ -1590,7 +1763,7 @@ void LoLEngine::snd_processEnvironmentalSoundEffect(int soundId, int block) {
int dist = 0;
if (block) {
dist = getMonsterDistance(_currentBlock, block);
- if (dist > _environmentSfxDistThreshold) {
+ if (dist > _envSfxDistThreshold) {
_environmentSfx = 0;
return;
}
@@ -1619,6 +1792,16 @@ void LoLEngine::snd_processEnvironmentalSoundEffect(int soundId, int block) {
snd_processEnvironmentalSoundEffect(0, 0);
}
+void LoLEngine::snd_queueEnvironmentalSoundEffect(int soundId, int block) {
+ if (_envSfxUseQueue && _envSfxNumTracksInQueue < 10) {
+ _envSfxQueuedTracks[_envSfxNumTracksInQueue] = soundId;
+ _envSfxQueuedBlocks[_envSfxNumTracksInQueue] = block;
+ _envSfxNumTracksInQueue++;
+ } else {
+ snd_processEnvironmentalSoundEffect(soundId, block);
+ }
+}
+
void LoLEngine::snd_loadSoundFile(int track) {
if (_sound->musicEnabled()) {
char filename[13];
@@ -1781,6 +1964,14 @@ const uint16 *LoLEngine::getCharacterOrMonsterStats(int id) {
return (id & 0x8000) ? (const uint16*)_monsters[id & 0x7fff].properties->fightingStats : _characters[id].defaultModifiers;
}
+uint16 *LoLEngine::getCharacterOrMonsterItemsMight(int id) {
+ return (id & 0x8000) ? _monsters[id & 0x7fff].properties->itemsMight : _characters[id].itemsMight;
+}
+
+uint16 *LoLEngine::getCharacterOrMonsterProtectionAgainstItems(int id) {
+ return (id & 0x8000) ? _monsters[id & 0x7fff].properties->protectionAgainstItems : _characters[id].protectionAgainstItems;
+}
+
void LoLEngine::delay(uint32 millis, bool cUpdate, bool isMainLoop) {
uint32 endTime = _system->getMillis() + millis;
while (endTime > _system->getMillis()) {
@@ -1820,6 +2011,120 @@ void LoLEngine::updateEnvironmentalSfx(int soundId) {
snd_processEnvironmentalSoundEffect(soundId, _currentBlock);
}
+void LoLEngine::processMagicHeal(int charNum, int points) {
+ if (!_healOverlay) {
+ _healOverlay = new uint8[256];
+ _screen->generateGrayOverlay(_screen->getPalette(1), _healOverlay, 52, 22, 20, 0, 256, true);
+ }
+
+ const uint8 *healShpFrames = 0;
+ const uint8 *healiShpFrames = 0;
+ bool resetFlag = false;
+ int maxDiff = 0;
+
+ if (points == 0) {
+ maxDiff = 25;
+ healShpFrames = _healShapeFrames;
+ healiShpFrames = _healShapeFrames + 32;
+
+ } else if (points == 1) {
+ maxDiff = 45;
+ healShpFrames = _healShapeFrames + 16;
+ healiShpFrames = _healShapeFrames + 48;
+
+ } else if (points > 3) {
+ resetFlag = true;
+ maxDiff = points;
+ healShpFrames = _healShapeFrames + 16;
+ healiShpFrames = _healShapeFrames + 64;
+
+ } else {
+ resetFlag = true;
+ maxDiff = 10000;
+ healShpFrames = _healShapeFrames + 16;
+ healiShpFrames = _healShapeFrames + 64;
+
+ }
+
+ int ch = 0;
+ int n = 4;
+
+ if (charNum != -1){
+ ch = charNum;
+ n = charNum + 1;
+ }
+
+ charNum = ch;
+
+ uint16 pX[4];
+ uint16 pY = 138;
+ uint16 diff[4];
+ uint16 pts[4];
+ memset(pts, 0, sizeof(pts));
+
+ while (charNum < n) {
+ if (!(_characters[charNum].flags & 1))
+ continue;
+
+ pX[charNum] = _activeCharsXpos[charNum] - 6;
+ _characters[charNum].damageSuffered = 0;
+ int dmg = _characters[charNum].hitPointsMax - _characters[charNum].hitPointsCur;
+ diff[charNum] = (dmg < maxDiff) ? dmg : maxDiff;
+ _screen->copyRegion(pX[charNum], pY, charNum * 77, 32, 77, 44, 0, 2, Screen::CR_NO_P_CHECK);
+ charNum++;
+ }
+
+ int cp = _screen->setCurPage(2);
+ snd_playSoundEffect(68, -1);
+
+ for (int i = 0; i < 16; i++) {
+ _smoothScrollTimer = _system->getMillis() + 4 * _tickLength;
+
+ for (charNum = ch; charNum < n; charNum++) {
+ if (!(_characters[charNum].flags & 1))
+ continue;
+
+ _screen->copyRegion(charNum * 77, 32, pX[charNum], pY, 77, 44, 2, 2, Screen::CR_NO_P_CHECK);
+
+ pts[charNum] &= 0xff;
+ pts[charNum] += ((diff[charNum] << 8) / 16);
+ increaseCharacterHitpoints(ch, pts[charNum] / 256, true);
+ gui_drawCharPortraitWithStats(charNum);
+
+ _screen->drawShape(2, _healShapes[healShpFrames[i]], pX[charNum], pY, 0, 0x1000, _trueLightTable1, _trueLightTable2);
+ _screen->fillRect(0, 0, 31, 31, 0);
+
+ _screen->drawShape(_screen->_curPage, _healiShapes[healiShpFrames[i]], 0, 0, 0, 0);
+ _screen->applyOverlaySpecial(_screen->_curPage, 0, 0, 2, pX[charNum] + 7, pY + 6, 32, 32, 0, 0, _healOverlay);
+
+ _screen->copyRegion(pX[charNum], pY, pX[charNum], pY, 77, 44, 2, 0, Screen::CR_NO_P_CHECK);
+ _screen->updateScreen();
+ }
+
+ while ((int)(_smoothScrollTimer - _system->getMillis()) > 0) {
+ updateInput();
+ delay(_tickLength);
+ }
+ }
+
+ for (charNum = ch; charNum < n; charNum++) {
+ if (!(_characters[charNum].flags & 1))
+ continue;
+
+ _screen->copyRegion(charNum * 77, 32, pX[charNum], pY, 77, 44, 2, 2, Screen::CR_NO_P_CHECK);
+
+ if (resetFlag)
+ resetCharacterState(&_characters[charNum], 4, 4);
+
+ gui_drawCharPortraitWithStats(charNum);
+ _screen->copyRegion(pX[charNum], pY, pX[charNum], pY, 77, 44, 2, 0, Screen::CR_NO_P_CHECK);
+ _screen->updateScreen();
+ }
+
+ _screen->setCurPage(cp);
+ updateDrawPage2();
+}
+
bool LoLEngine::notEnoughMagic(int charNum, int spellNum, int spellLevel) {
if (_spellProperties[spellNum].mpRequired[spellLevel] > _characters[charNum].magicPointsCur) {
if (characterSays(0x4043, _characters[charNum].id, true))
@@ -1833,6 +2138,8 @@ bool LoLEngine::notEnoughMagic(int charNum, int spellNum, int spellLevel) {
return false;
}
+// fight
+
int LoLEngine::battleHitSkillTest(int16 attacker, int16 target, int skill) {
if (target == -1)
return 0;
@@ -1879,28 +2186,440 @@ int LoLEngine::battleHitSkillTest(int16 attacker, int16 target, int skill) {
}
int LoLEngine::calcInflictableDamage(int16 attacker, int16 target, int hitType) {
- const uint16 *s = getCharacterOrMonsterStats(attacker);
+ const uint16 *s = getCharacterOrMonsterItemsMight(attacker);
- int res = 0;
+ // The original code looks somewhat like the commented out part of the next line.
+ // In the end the value is always set to zero. I do not know whether this is done on purpose or not.
+ // It might be a bug in the original code.
+ int res = 0/*attacker & 0x8000 ? 0 : _characters[attacker].might*/;
for (int i = 0; i < 8; i++)
- res += calcInflictableDamagePerStat(attacker, target, s[2 + i], i, hitType);
+ res += calcInflictableDamagePerItem(attacker, target, s[i], i, hitType);
return res;
}
-void LoLEngine::battleHit_sub2(int16 target, int damageInflicted, int16 attacker, uint32 b) {
+int LoLEngine::inflictDamage(int16 target, int damage, int16 attacker, int skill, int deathFlag) {
+ MonsterInPlay *m = 0;
+ LoLCharacter *c = 0;
+
+ if (target & 0x8000) {
+ m = &_monsters[target & 0x7fff];
+ if (m->mode >= 13)
+ return 0;
+
+ if (damage > 0) {
+ m->hitPoints -= damage;
+ m->damageReceived = 0x8000 | damage;
+ m->flags |= 0x10;
+ m->hitOffsX = _rnd.getRandomNumberRng(1, 24);
+ m->hitOffsX -= 12;
+ m->hitOffsY = _rnd.getRandomNumberRng(1, 24);
+ m->hitOffsY -= 12;
+ m->hitPoints = CLIP<int16>(m->hitPoints, 0, m->properties->hitPoints);
+
+ if (!(attacker & 0x8000))
+ applyMonsterDefenseSkill(m, attacker, deathFlag, skill, damage);
+
+ snd_queueEnvironmentalSoundEffect(m->properties->sounds[2], m->block);
+ checkSceneUpdateNeed(m->block);
+
+ if (m->hitPoints <= 0) {
+ m->hitPoints = 0;
+ if (!(attacker & 0x8000))
+ increaseExperience(attacker, skill, m->properties->hitPoints);
+ setMonsterMode(m, 13);
+ }
+ } else {
+ m->hitPoints -= damage;
+ m->hitPoints = CLIP<int16>(m->hitPoints, 1, m->properties->hitPoints);
+ }
+
+ } else {
+ c = &_characters[target];
+ if (!(c->flags & 1) || (c->flags & 8))
+ return 0;
+
+ if (!(c->flags & 0x1000))
+ snd_playSoundEffect(c->screamSfx, -1);
+
+ setTemporaryFaceFrame(target, 6, 4, 0);
+
+ // check for equipped cloud ring
+ if (deathFlag == 4 && itemEquipped(target, 229))
+ damage >>= 2;
+
+ setCharacterMagicOrHitPoints(target, 0, -damage, 1);
+
+ if (c->hitPointsCur <= 0) {
+ characterHitpointsZero(target, deathFlag);
+ } else {
+ _characters[target].damageSuffered = damage;
+ setCharacterUpdateEvent(target, 2, 4, 1);
+ }
+ gui_drawCharPortraitWithStats(target);
+ }
+
+ if (!(attacker & 0x8000)) {
+ if (!skill)
+ _characters[attacker].weaponHit = damage;
+ increaseExperience(attacker, skill, damage);
+ }
+
+ return damage;
+}
+
+void LoLEngine::characterHitpointsZero(int16 charNum, int deathFlag) {
+ LoLCharacter *c = &_characters[charNum];
+ c->hitPointsCur = 0;
+ c->flags |= 8;
+ resetCharacterState(c, 1, 5);
+ _partyDeathFlag = deathFlag;
+}
+
+void LoLEngine::resetCharacterState(LoLCharacter *c, int first, int last) {
+ for (int i = first; i <= last; i++) {
+ switch (i - 1) {
+ case 0:
+ c->weaponHit = 0;
+ break;
+
+ case 1:
+ c->damageSuffered = 0;
+ break;
+
+ case 2:
+ c->flags &= 0xffbf;
+ break;
+
+ case 3:
+ c->flags &= 0xff7f;
+ break;
+
+ case 4:
+ c->flags &= 0xfeff;
+ break;
+
+ case 6:
+ c->flags &= 0xefff;
+ break;
+
+ default:
+ break;
+ }
+
+ for (int ii = 0; ii < 5; ii++) {
+ if (i != c->characterUpdateEvents[ii])
+ continue;
+
+ c->characterUpdateEvents[ii] = 0;
+ c->characterUpdateDelay[ii] = 0;
+ }
+ }
+ _timer3Para = 1;
+ _timer->enable(3);
}
-void LoLEngine::battleHit_sub3(MonsterInPlay *monster, int16 target, int16 damageInflicted) {
+int LoLEngine::calcInflictableDamagePerItem(int16 attacker, int16 target, uint16 itemMight, int index, int hitType) {
+ int dmg = (attacker == -1) ? 0x100 : getCharacterOrMonsterStats(attacker)[1];
+ const uint16 *st_t = getCharacterOrMonsterProtectionAgainstItems(target);
+
+ dmg = (dmg * itemMight) >> 8;
+ if (!dmg)
+ return 0;
+
+ if (!(attacker & 0x8000)) {
+ dmg = (dmg * _characters[attacker].totalMightModifier) >> 8;
+ if (!dmg)
+ return 0;
+ }
+
+ int d = (index & 0x80) ? st_t[7] : st_t[index];
+ int r = (dmg * ABS(d)) >> 8;
+ dmg = d < 0 ? -r : r;
+
+ if (hitType == 2 || !dmg)
+ return (dmg == 1) ? 2 : dmg;
+
+ int p = (calculateProtection(target) << 7) / dmg;
+ if (p > 217)
+ p = 217;
+
+ d = 256 - p;
+ r = (dmg * ABS(d)) >> 8;
+ dmg = d < 0 ? -r : r;
+
+ return (dmg < 2) ? 2 : dmg;
}
-int LoLEngine::calcInflictableDamagePerStat(int16 attacker, int16 target, uint16 stat2m, int index, int hitType) {
- return 1;
+void LoLEngine::checkForPartyDeath() {
+
}
-uint16 LoLEngine::getClosestMonster(int x, int y) {
+void LoLEngine::applyMonsterAttackSkill(MonsterInPlay *monster, int16 target, int16 damage) {
+ if (_rnd.getRandomNumberRng(1, 100) > monster->properties->attackSkillChance)
+ return;
+
+ int t = 0;
+
+ switch (monster->properties->attackSkillType - 1) {
+ case 0:
+ t = removeCharacterItem(target, 0x7ff);
+ if (t) {
+ giveItemToMonster(monster, t);
+ if (characterSays(0x4019, _characters[target].id, true))
+ _txt->printMessage(6, getLangString(0x4019));
+ }
+ break;
+
+ case 1:
+ // poison character
+ paralyzePoisonCharacter(target, 0x80, 0x88, 100, 1);
+ break;
+
+ case 2:
+ t = removeCharacterItem(target, 0x20);
+ if (t) {
+ deleteItem(t);
+ if (characterSays(0x401b, _characters[target].id, true))
+ _txt->printMessage(6, getLangString(0x401b));
+ }
+ break;
+
+ case 3:
+ t = removeCharacterItem(target, 0x0f);
+ if (t) {
+ if (characterSays(0x401e, _characters[target].id, true))
+ _txt->printMessage(6, getLangString(0x401e), _characters[target].name);
+ setItemPosition(t, monster->x, monster->y, 0, 1);
+ }
+ break;
+
+ case 5:
+ if (_characters[target].magicPointsCur <= 0)
+ return;
+
+ monster->hitPoints += _characters[target].magicPointsCur;
+ _characters[target].magicPointsCur = 0;
+ gui_drawCharPortraitWithStats(target);
+ if (characterSays(0x4020, _characters[target].id, true))
+ _txt->printMessage(6, getLangString(0x4020), _characters[target].name);
+ break;
+
+ case 7:
+ stunCharacter(target);
+ break;
+
+ case 8:
+ monster->hitPoints += damage;
+ if (monster->hitPoints > monster->properties->hitPoints)
+ monster->hitPoints = monster->properties->hitPoints;
+
+ break;
+
+ case 9:
+ // paralyze party (spider web)
+ paralyzePoisonAllCharacters(0x40, 0x48, 100);
+ break;
+
+ default:
+ break;
+ }
+}
+
+void LoLEngine::applyMonsterDefenseSkill(MonsterInPlay *monster, int16 attacker, int deathFlag, int skill, int damage) {
+ if (_rnd.getRandomNumberRng(1, 100) > monster->properties->defenseSkillChance)
+ return;
+
+ int itm = 0;
+
+ switch (monster->properties->defenseSkillType - 1) {
+ case 0:
+ case 1:
+ if ((deathFlag & 0x3f) == 2 || skill)
+ return;
+
+ for (int i = 0; i < 3 ; i++) {
+ itm = _characters[attacker].items[i];
+ if (!itm)
+ continue;
+ if ((_itemProperties[_itemsInPlay[itm].itemPropertyIndex].protection & 0x3f) != deathFlag)
+ continue;
+
+ removeCharacterItem(attacker, 0x7fff);
+
+ if (monster->properties->defenseSkillType == 1) {
+ deleteItem(itm);
+ if (characterSays(0x401d, _characters[attacker].id, true))
+ _txt->printMessage(6, getLangString(0x401d));
+ } else {
+ giveItemToMonster(monster, itm);
+ if (characterSays(0x401c, _characters[attacker].id, true))
+ _txt->printMessage(6, getLangString(0x401c));
+ }
+ }
+ break;
+
+ case 2:
+ if (!(deathFlag & 0x80))
+ return;
+ monster->flags |= 8;
+ monster->direction = calcMonsterDirection(monster->x, monster->y, _partyPosX, _partyPosY) ^ 4;
+ setMonsterMode(monster, 9);
+ monster->fightCurTick = 30;
+ break;
+
+ case 3:
+ if (deathFlag != 3)
+ return;
+ monster->hitPoints += damage;
+ if (monster->hitPoints > monster->properties->hitPoints)
+ monster->hitPoints = monster->properties->hitPoints;
+
+
+ break;
+
+ case 4:
+ if (!(deathFlag & 0x80))
+ return;
+ monster->hitPoints += damage;
+ if (monster->hitPoints > monster->properties->hitPoints)
+ monster->hitPoints = monster->properties->hitPoints;
+ break;
+
+ case 5:
+ if ((deathFlag & 0x84) == 0x84)
+ monster->numDistAttacks++;
+ break;
+
+ default:
+ break;
+ }
+}
+
+int LoLEngine::removeCharacterItem(int charNum, int itemFlags) {
+ for (int i = 0; i < 11; i++) {
+ int s = _characters[charNum].items[i];
+ if (!((1 << i) & itemFlags) || !s)
+ continue;
+
+ _characters[charNum].items[i] = 0;
+ runItemScript(charNum, s, 0x100, 0, 0);
+
+ return s;
+ }
+
+ return 0;
+}
+
+bool LoLEngine::paralyzePoisonCharacter(int charNum, int typeFlag, int immunityFlags, int hitChance, int redraw) {
+ if (!(_characters[charNum].flags & 1) || (_characters[charNum].flags & immunityFlags))
+ return 0;
+
+ if ((int)_rnd.getRandomNumberRng(1, 100) > hitChance)
+ return 0;
+
+ int r = false;
+
+ if (typeFlag == 0x40) {
+ _characters[charNum].flags |= 0x40;
+ setCharacterUpdateEvent(charNum, 3, 3600, 1);
+ r = true;
+
+ // check for bezel ring
+ } else if (typeFlag == 0x80 && !itemEquipped(charNum, 225)) {
+ _characters[charNum].flags |= 0x80;
+ setCharacterUpdateEvent(charNum, 4, 10, 1);
+ if (characterSays(0x4021, _characters[charNum].id, true))
+ _txt->printMessage(6, getLangString(0x4021), _characters[charNum].name);
+ r = true;
+
+ } else if (typeFlag == 0x1000) {
+ _characters[charNum].flags |= 0x1000;
+ setCharacterUpdateEvent(charNum, 7, 120, 1);
+ r = true;
+ }
+
+ if (r && redraw)
+ gui_drawCharPortraitWithStats(charNum);
+
+ return r;
+}
+
+void LoLEngine::paralyzePoisonAllCharacters(int typeFlag, int immunityFlags, int hitChance) {
+ bool r = false;
+ for (int i = 0; i < 4; i++) {
+ if (paralyzePoisonCharacter(i, typeFlag, immunityFlags, hitChance, 0))
+ r = true;
+ }
+ if (r)
+ gui_drawAllCharPortraitsWithStats();
+}
+
+void LoLEngine::stunCharacter(int charNum) {
+ if (!(_characters[charNum].flags & 1) || (_characters[charNum].flags & 0x108))
+ return;
+
+ _characters[charNum].flags |= 0x100;
+
+ setCharacterUpdateEvent(charNum, 5, 20, 1);
+ gui_drawCharPortraitWithStats(charNum);
+
+ _txt->printMessage(6, getLangString(0x4026), _characters[charNum].name);
+}
+
+void LoLEngine::level11specialUnk() {
+
+}
+
+void LoLEngine::distObj1Sub(int a, int b, int c, int d) {
+
+}
+
+void LoLEngine::launchMagicViper() {
+
+}
+
+void LoLEngine::attackWall(int a, int b) {
+
+}
+
+uint16 LoLEngine::getNearestMonsterFromCharacter(int charNum) {
+ return getNearestMonsterFromCharacterForBlock(calcNewBlockPosition(_currentBlock, _currentDirection), charNum);
+}
+
+uint16 LoLEngine::getNearestMonsterFromCharacterForBlock(int block, int charNum) {
+ uint16 cX = 0;
+ uint16 cY = 0;
+
+ uint16 id = 0xffff;
+ int minDist = 0x7fff;
+
+ calcCoordinatesForSingleCharacter(charNum, cX, cY);
+
+ int o = _levelBlockProperties[block].assignedObjects;
+
+ while (o & 0x8000) {
+ MonsterInPlay *m = &_monsters[o & 0x7fff];
+ if (m->mode >= 13) {
+ o = m->nextAssignedObject;
+ continue;
+ }
+
+ int d = ABS(cX - m->x) + ABS(cY - m->y);
+ if (d < minDist) {
+ minDist = d;
+ id = o;
+ }
+
+ o = m->nextAssignedObject;
+ }
+
+ return id;
+}
+
+uint16 LoLEngine::getNearestMonsterFromPos(int x, int y) {
uint16 id = 0xffff;
int minDist = 0x7fff;
@@ -1918,7 +2637,7 @@ uint16 LoLEngine::getClosestMonster(int x, int y) {
return id;
}
-uint16 LoLEngine::getClosestPartyMember(int x, int y) {
+uint16 LoLEngine::getNearestPartyMemberFromPos(int x, int y) {
uint16 id = 0xffff;
int minDist = 0x7fff;
@@ -1940,50 +2659,6 @@ uint16 LoLEngine::getClosestPartyMember(int x, int y) {
return id;
}
-void LoLEngine::generateTempData() {
- int l = _currentLevel - 1;
- if (_lvlTempData[l]) {
- delete[] _lvlTempData[l]->wallsXorData;
- delete[] _lvlTempData[l]->flags;
- delete[] _lvlTempData[l]->monsters;
- delete[] _lvlTempData[l]->flyingObjects;
- delete _lvlTempData[l];
- }
-
- _lvlTempData[l] = new LevelTempData;
-
- _lvlTempData[l]->wallsXorData = new uint8[4096];
- _lvlTempData[l]->flags = new uint8[1024];
- _lvlTempData[l]->monsters = new MonsterInPlay[30];
- _lvlTempData[l]->flyingObjects = new FlyingObject[8];
-
- char filename[13];
- snprintf(filename, sizeof(filename), "LEVEL%d.CMZ", _currentLevel);
-
- _screen->loadBitmap(filename, 3, 3, 0);
- const uint8 *p = _screen->getCPagePtr(2);
- uint16 len = READ_LE_UINT16(p + 4);
- p += 6;
-
- memset(_lvlTempData[l]->wallsXorData, 0, 4096);
- memset(_lvlTempData[l]->flags, 0, 1024);
- uint8 *d = _lvlTempData[l]->wallsXorData;
- uint8 *df = _lvlTempData[l]->flags;
-
- for (int i = 0; i < 1024; i++) {
- for (int ii = 0; ii < 4; ii++)
- *d++ = p[i * len + ii] ^ _levelBlockProperties[i].walls[ii];
- *df++ = _levelBlockProperties[i].flags;
- }
-
- memcpy(_lvlTempData[l]->monsters, _monsters, sizeof(MonsterInPlay) * 30);
- memcpy(_lvlTempData[l]->flyingObjects, _flyingObjects, sizeof(FlyingObject) * 8);
-
- _lvlTempData[l]->monsterDifficulty =_monsterDifficulty;
-
- _hasTempDataFlags |= (1 << l);
-}
-
// magic atlas
void LoLEngine::displayAutomap() {
@@ -2056,7 +2731,7 @@ void LoLEngine::displayAutomap() {
exitAutomap = true;
}
- delay (_tickLength);
+ delay(_tickLength);
}
_screen->loadFont(Screen::FID_9_FNT, "FONT9P.FNT");
@@ -2468,6 +3143,50 @@ void LoLEngine::printMapExitButtonText() {
_screen->setCurPage(cp);
}
+void LoLEngine::generateTempData() {
+ int l = _currentLevel - 1;
+ if (_lvlTempData[l]) {
+ delete[] _lvlTempData[l]->wallsXorData;
+ delete[] _lvlTempData[l]->flags;
+ delete[] _lvlTempData[l]->monsters;
+ delete[] _lvlTempData[l]->flyingObjects;
+ delete _lvlTempData[l];
+ }
+
+ _lvlTempData[l] = new LevelTempData;
+
+ _lvlTempData[l]->wallsXorData = new uint8[4096];
+ _lvlTempData[l]->flags = new uint8[1024];
+ _lvlTempData[l]->monsters = new MonsterInPlay[30];
+ _lvlTempData[l]->flyingObjects = new FlyingObject[8];
+
+ char filename[13];
+ snprintf(filename, sizeof(filename), "LEVEL%d.CMZ", _currentLevel);
+
+ _screen->loadBitmap(filename, 3, 3, 0);
+ const uint8 *p = _screen->getCPagePtr(2);
+ uint16 len = READ_LE_UINT16(p + 4);
+ p += 6;
+
+ memset(_lvlTempData[l]->wallsXorData, 0, 4096);
+ memset(_lvlTempData[l]->flags, 0, 1024);
+ uint8 *d = _lvlTempData[l]->wallsXorData;
+ uint8 *df = _lvlTempData[l]->flags;
+
+ for (int i = 0; i < 1024; i++) {
+ for (int ii = 0; ii < 4; ii++)
+ *d++ = p[i * len + ii] ^ _levelBlockProperties[i].walls[ii];
+ *df++ = _levelBlockProperties[i].flags;
+ }
+
+ memcpy(_lvlTempData[l]->monsters, _monsters, sizeof(MonsterInPlay) * 30);
+ memcpy(_lvlTempData[l]->flyingObjects, _flyingObjects, sizeof(FlyingObject) * 8);
+
+ _lvlTempData[l]->monsterDifficulty =_monsterDifficulty;
+
+ _hasTempDataFlags |= (1 << l);
+}
+
} // end of namespace Kyra
#endif // ENABLE_LOL