LOL: - implemented freeze spell

- fixed saveload code
- added some opcode for the swamp

svn-id: r40763
This commit is contained in:
Florian Kagerer 2009-05-21 16:46:40 +00:00
parent 6e93825b2e
commit 6bd5dea027
11 changed files with 259 additions and 51 deletions

View File

@ -1048,7 +1048,7 @@ int LoLEngine::clickedAttackButton(Button *button) {
int bl = calcNewBlockPosition(_currentBlock, _currentDirection);
if (_levelBlockProperties[bl].flags & 0x10) {
attackWall(0, 0);
breakIceWall(0, 0);
return 1;
}
@ -1750,6 +1750,7 @@ int LoLEngine::clickedAutomap(Button *button) {
if (!(_gameFlags[15] & 0x1000))
return 0;
removeInputTop();
displayAutomap();
gui_drawPlayField();

View File

@ -123,7 +123,7 @@ LoLEngine::LoLEngine(OSystem *system, const GameFlags &flags) : KyraEngine_v1(sy
_lastButtonShape = 0;
_buttonPressTimer = 0;
_selectedCharacter = 0;
_unkFlag = 0;
_gameFlags[36] = 0;
_suspendScript = _sceneUpdateRequired = false;
_scriptDirection = 0;
_currentDirection = 0;
@ -226,7 +226,7 @@ LoLEngine::LoLEngine(OSystem *system, const GameFlags &flags) : KyraEngine_v1(sy
_floatingCursorsEnabled = false;
memset(_lvlTempData, 0, sizeof(_lvlTempData));
_freezeStateFlags = 0;
_gameFlags[26] = 0;
_mapOverlay = 0;
_automapShapes = 0;
@ -868,7 +868,7 @@ void LoLEngine::runLoop() {
enableSysTimer(2);
bool _runFlag = true;
_unkFlag |= 0x800;
_gameFlags[36] |= 0x800;
while (!shouldQuit() && _runFlag) {
if (_nextScriptFunc) {
@ -2411,26 +2411,143 @@ void LoLEngine::processMagicIce(int charNum, int spellLevel) {
gui_drawScene(0);
_screen->copyPage(0, 12);
//uint8 pal2[768];
//uint8 pal3[768];
uint8 *tpal = new uint8[768];
uint8 *swampCol = new uint8[768];
if (_currentLevel == 11 && !(_freezeStateFlags & 4)) {
for (int i = 1; i < 384; i++) {
///////// TODO
}
_freezeStateFlags |= 4;
if (_currentLevel == 11 && !(_gameFlags[26] & 4)) {
uint8 *sc = _screen->_currentPalette;
uint8 *dc = _screen->getPalette(2);
for (int i = 1; i < 768; i++)
SWAP(sc[i], dc[i]);
_gameFlags[26] |= 4;
static const uint8 freezeTimes[] = { 20, 28, 40, 60 };
setCharacterUpdateEvent(charNum, 8, freezeTimes[spellLevel], 1);
}
////////// TODO
generateBrightnessPalette(_screen->_currentPalette, _screen->getPalette(1), _brightness, _lampEffect);
uint8 *sc = _res->fileData("swampice.col", 0);
memcpy(swampCol, sc, 384);
uint8 *s = _screen->getPalette(1);
for (int i = 384; i < 768; i++)
swampCol[i] = tpal[i] = s[i] & 0x3f;
////////// TODO
for (int i = 1; i < 128; i++) {
tpal[i * 3] = 0;
uint16 v = (s[i * 3] + s[i * 3 + 1] + s[i * 3 + 2]) / 3;
tpal[i * 3 + 1] = v;
tpal[i * 3 + 2] = v << 1;
if (tpal[i * 3 + 2] > 0x3f)
tpal[i * 3 + 2] = 0x3f;
}
generateBrightnessPalette(tpal, tpal, _brightness, _lampEffect);
generateBrightnessPalette(swampCol, swampCol, _brightness, _lampEffect);
swampCol[0] = swampCol[1] = swampCol[2] = tpal[0] = tpal[1] = tpal[2] = 0;
generateBrightnessPalette(_screen->_currentPalette, s, _brightness, _lampEffect);
int sX = 112;
int sY = 0;
WSAMovie_v2 *mov = new WSAMovie_v2(this, _screen);
if (spellLevel == 0) {
sX = 0;
} if (spellLevel == 1 || spellLevel == 2) {
mov->open("snow.wsa", 1, 0);
if (!mov->opened())
error("Ice: Unable to load snow.wsa");
} if (spellLevel == 3) {
mov->open("ice.wsa", 1, 0);
if (!mov->opened())
error("Ice: Unable to load ice.wsa");
sX = 136;
sY = 12;
}
snd_playSoundEffect(71, -1);
playSpellAnimation(0, 0, 0, 2, 0, 0, 0, s, tpal, 40, false);
_screen->fadePaletteStep(s, tpal, _system->getMillis(), _tickLength);
if (mov->opened()) {
int r = true;
if (spellLevel > 2) {
_levelBlockProperties[calcNewBlockPosition(_currentBlock, _currentDirection)].flags |= 0x10;
snd_playSoundEffect(165, -1);
r = false;
};
playSpellAnimation(mov, 0, mov->frames(), 2, sX, sY, 0, 0, 0, 0, r);
mov->close();
}
delete mov;
static const uint8 snowDamage[] = { 10, 20, 30, 55 };
static const uint8 iceDamageMax[] = {1, 2, 15, 20, 35};
static const uint8 iceDamageMin[] = {10, 10, 3, 4, 4};
static const uint8 iceDamageAdd[] = {5, 10, 30, 10, 10};
bool breakWall = false;
if (spellLevel < 3) {
inflictMagicalDamageForBlock(calcNewBlockPosition(_currentBlock, _currentDirection), charNum, snowDamage[spellLevel], 3);
} else {
uint16 o = _levelBlockProperties[calcNewBlockPosition(_currentBlock, _currentDirection)].assignedObjects;
while (o & 0x8000) {
int might = _rnd.getRandomNumberRng(iceDamageMin[spellLevel], iceDamageMax[spellLevel]) + iceDamageAdd[spellLevel];
int dmg = calcInflictableDamagePerItem(charNum, 0, might, 3, 2);
MonsterInPlay *m = &_monsters[o & 0x7fff];
if (m->hitPoints <= dmg) {
increaseExperience(charNum, 2, m->hitPoints);
o = m->nextAssignedObject;
if (m->flags & 0x20) {
m->mode = 0;
monsterDropItems(m);
if (_currentLevel != 29)
setMonsterMode(m, 14);
runLevelScriptCustom(0x404, -1, o, o, 0, 0);
checkSceneUpdateNeed(m->block);
if (m->mode != 14)
placeMonster(m, 0, 0);
} else {
killMonster(m);
}
} else {
breakWall = true;
inflictDamage(o, dmg, charNum, 2, 3);
m->damageReceived = 0;
o = m->nextAssignedObject;
}
if (m->flags & 0x20)
break;
}
}
updateDrawPage2();
gui_drawScene(0);
enableSysTimer(2);
if (_currentLevel != 11)
generateBrightnessPalette(_screen->_currentPalette, swampCol, _brightness, _lampEffect);
playSpellAnimation(0, 0, 0, 2, 0, 0, 0, tpal, swampCol, 40, 0);
_screen->fadePaletteStep(tpal, swampCol, _system->getMillis(), _tickLength);
if (breakWall)
breakIceWall(tpal, swampCol);
static const uint8 freezeTime[] = { 20, 28, 40, 60 };
if (_currentLevel == 11)
setCharacterUpdateEvent(charNum, 8, freezeTime[spellLevel], 1);
delete[] sc;
delete[] swampCol;
delete[] tpal;
_screen->setCurPage(cp);
}
@ -2724,15 +2841,15 @@ void LoLEngine::playSpellAnimation(WSAMovie_v2 *mov, int firstFrame, int lastFra
int step = del > _tickLength ? _tickLength : del;
if (!pal1 || !pal2) {
delay(step);
delay(step, false, true);
del -= step;
continue;
}
if (!_screen->fadePalSpecial(pal1, pal2, _system->getMillis() - startTime, _tickLength * fadeDelay) && !mov)
if (!_screen->fadePaletteStep(pal1, pal2, _system->getMillis() - startTime, _tickLength * fadeDelay) && !mov)
return;
delay(step);
delay(step, false, true);
del -= step;
} while (del > 0);
@ -2793,6 +2910,16 @@ void LoLEngine::inflictMagicalDamage(int target, int attacker, int damage, int i
inflictDamage(target, damage, attacker, 2, index);
}
void LoLEngine::inflictMagicalDamageForBlock(int block, int attacker, int damage, int index) {
uint16 o = _levelBlockProperties[block].assignedObjects;
while (o & 0x8000) {
inflictDamage(o, calcInflictableDamagePerItem(attacker, o, damage, index, 2), attacker, 2, index);
if ((_monsters[o & 0x7fff].flags & 0x20) && (_currentLevel != 22))
break;
o = _monsters[o & 0x7fff].nextAssignedObject;
}
}
// fight
int LoLEngine::battleHitSkillTest(int16 attacker, int16 target, int skill) {
@ -3221,13 +3348,49 @@ void LoLEngine::stunCharacter(int charNum) {
_txt->printMessage(6, getLangString(0x4026), _characters[charNum].name);
}
void LoLEngine::level11specialUnk() {
void LoLEngine::restoreSwampPalette() {
_gameFlags[26] &= 0xfffb;
if (_currentLevel != 11)
return;
uint8 *s = _screen->getPalette(2);
uint8 *d = _screen->_currentPalette;
uint8 *d2 = _screen->getPalette(1);
for (int i = 1; i < 768; i++)
SWAP(s[i], d[i]);
generateBrightnessPalette(d, d2, _brightness, _lampEffect);
_screen->loadSpecialColors(s);
_screen->loadSpecialColors(d2);
playSpellAnimation(0, 0, 0, 2, 0, 0, 0, s, d2, 40, 0);
}
void LoLEngine::launchMagicViper() {
}
void LoLEngine::attackWall(int a, int b) {
void LoLEngine::breakIceWall(uint8 *pal1, uint8 *pal2) {
_screen->hideMouse();
uint16 bl = calcNewBlockPosition(_currentBlock, _currentDirection);
_levelBlockProperties[bl].flags &= 0xef;
_screen->copyPage(0, 2);
gui_drawScene(2);
_screen->copyPage(2, 10);
WSAMovie_v2 *mov = new WSAMovie_v2(this, _screen);
int numFrames = mov->open("shatter.wsa", 1, 0);
if (!mov->opened())
error("Shatter: Unable to load shatter.wsa");
snd_playSoundEffect(166, -1);
playSpellAnimation(mov, 0, numFrames, 1, 58, 0, 0, pal1, pal2, 20, true);
mov->close();
delete mov;
_screen->copyPage(10, 0);
updateDrawPage2();
gui_drawScene(0);
_screen->showMouse();
}
uint16 LoLEngine::getNearestMonsterFromCharacter(int charNum) {

View File

@ -568,7 +568,7 @@ private:
uint16 _currentBlock;
bool _sceneUpdateRequired;
int16 _visibleBlockIndex[18];
uint16 _gameFlags[16];
uint16 _gameFlags[40];
int16 _globalScriptVars[24];
// emc opcode
@ -639,6 +639,7 @@ private:
int olol_createHandItem(EMCState *script);
int olol_playAttackSound(EMCState *script);
int olol_characterJoinsParty(EMCState *script);
int olol_giveItem(EMCState *script);
int olol_loadTimScript(EMCState *script);
int olol_runTimScript(EMCState *script);
int olol_releaseTimScript(EMCState *script);
@ -710,6 +711,7 @@ private:
int olol_getNextActiveCharacter(EMCState *script);
int olol_paralyzePoisonCharacter(EMCState *script);
int olol_drawCharPortrait(EMCState *script);
int olol_placeInventoryItemInHand(EMCState *script);
int olol_castSpell(EMCState *script);
int olol_pitDrop(EMCState *script);
int olol_paletteFlash(EMCState *script);
@ -967,7 +969,6 @@ private:
const uint8 *_scrollYBottom;
int _scrollYBottomSize;
int _unkFlag;
int _nextScriptFunc;
uint8 _currentLevel;
int _sceneDefaultUpdate;
@ -1270,6 +1271,8 @@ private:
int checkMagic(int charNum, int spellNum, int spellLevel);
int getSpellTargetBlock(int currentBlock, int direction, int maxDistance, uint16 &targetBlock);
void inflictMagicalDamage(int target, int attacker, int damage, int index, int hitType);
void inflictMagicalDamageForBlock(int block, int attacker, int damage, int index);
ActiveSpell _activeSpell;
int8 _availableSpells[7];
@ -1278,7 +1281,6 @@ private:
int _spellPropertiesSize;
int _subMenuIndex;
uint16 _freezeStateFlags;
uint8 *_healOverlay;
uint8 _swarmSpellStatus;
@ -1311,12 +1313,12 @@ private:
int paralyzePoisonCharacter(int charNum, int typeFlag, int immunityFlags, int hitChance, int redraw);
void paralyzePoisonAllCharacters(int typeFlag, int immunityFlags, int hitChance);
void stunCharacter(int charNum);
void level11specialUnk();
void restoreSwampPalette();
void distObj1Sub(int a, int b, int c, int d);
void launchMagicViper();
void attackWall(int a, int b);
void breakIceWall(uint8 *pal1, uint8 *pal2);
uint16 getNearestMonsterFromCharacter(int charNum);
uint16 getNearestMonsterFromCharacterForBlock(uint16 block, int charNum);

View File

@ -30,7 +30,7 @@
#include "kyra/kyra_v1.h"
#define CURRENT_SAVE_VERSION 14
#define CURRENT_SAVE_VERSION 15
#define GF_FLOPPY (1 << 0)
#define GF_TALKIE (1 << 1)

View File

@ -119,10 +119,15 @@ Common::Error LoLEngine::loadGameState(int slot) {
_inventoryCurItem = in.readSint16BE();
_itemInHand = in.readSint16BE();
_lastMouseRegion = in.readSint16BE();
for (int i = 0; i < 16; i++)
_gameFlags[i] = in.readUint16BE();
_freezeStateFlags = in.readUint16BE();
_unkFlag = in.readUint16BE();
if (header.version == 14) {
for (int i = 0; i < 16; i++)
_gameFlags[i] = in.readUint16BE();
_gameFlags[26] = in.readUint16BE();
_gameFlags[36] = in.readUint16BE();
} else {
for (int i = 0; i < 40; i++)
_gameFlags[i] = in.readUint16BE();
}
for (int i = 0; i < 24; i++)
_globalScriptVars[i] = in.readUint16BE();
_brightness = in.readByte();
@ -240,7 +245,7 @@ Common::Error LoLEngine::loadGameState(int slot) {
loadLevel(_currentLevel);
gui_drawPlayField();
timerSpecialCharacterUpdate(0);
_unkFlag |= 0x800;
_gameFlags[36] |= 0x800;
while (!_screen->isMouseVisible())
_screen->showMouse();
@ -318,10 +323,8 @@ Common::Error LoLEngine::saveGameState(int slot, const char *saveName, const Gra
out->writeSint16BE(_inventoryCurItem);
out->writeSint16BE(_itemInHand);
out->writeSint16BE(_lastMouseRegion);
for (int i = 0; i < 16; i++)
for (int i = 0; i < 40; i++)
out->writeUint16BE(_gameFlags[i]);
out->writeUint16BE(_freezeStateFlags);
out->writeUint16BE(_unkFlag);
for (int i = 0; i < 24; i++)
out->writeUint16BE(_globalScriptVars[i]);
out->writeByte(_brightness);

View File

@ -36,7 +36,7 @@
namespace Kyra {
void LoLEngine::loadLevel(int index) {
_unkFlag |= 0x800;
_gameFlags[36] |= 0x800;
setMouseCursorToIcon(0x85);
_nextScriptFunc = 0;
@ -395,10 +395,10 @@ void LoLEngine::loadLevelGraphics(const char *file, int specialColor, int weight
if (_currentLevel == 11) {
uint8 *swampPal = _res->fileData("SWAMPICE.COL", 0);
memcpy(_screen->getPalette(2), swampPal, 384);
memcpy(_screen->getPalette(2) + 0x180, _screen->_currentPalette, 384);
memcpy(_screen->getPalette(2) + 384, _screen->_currentPalette + 384, 384);
delete[] swampPal;
if (_freezeStateFlags & 4) {
if (_gameFlags[26] & 4) {
uint8 *pal0 = _screen->_currentPalette;
uint8 *pal2 = _screen->getPalette(2);
for (int i = 1; i < 768; i++)
@ -651,12 +651,12 @@ void LoLEngine::moveParty(uint16 direction, int unk1, int unk2, int buttonShape)
_sceneDefaultUpdate = 1;
calcCoordinates(_partyPosX, _partyPosY, _currentBlock, 0x80, 0x80);
_unkFlag &= 0xfdff;
_gameFlags[36] &= 0xfdff;
runLevelScript(opos, 4);
runLevelScript(npos, 1);
if (!(_unkFlag & 0x200)) {
if (!(_gameFlags[36] & 0x200)) {
initTextFading(2, 0);
if (_sceneDefaultUpdate) {

View File

@ -815,20 +815,20 @@ bool Screen_LoL::fadeColor(int dstColorIndex, int srcColorIndex, uint32 elapsedT
return res;
}
bool Screen_LoL::fadePalSpecial(uint8 *pal1, uint8 *pal2, uint32 elapsedTime, uint32 targetTime) {
bool Screen_LoL::fadePaletteStep(uint8 *pal1, uint8 *pal2, uint32 elapsedTime, uint32 targetTime) {
uint8 tpal[768];
uint8 *p1 = _palettes[1];
uint8 *p1 = _palettes[0];
bool res = false;
for (int i = 0; i < 768; i++) {
uint8 out = 0;
if (elapsedTime < targetTime) {
int d = (pal2[i] & 0x3f) - (pal1[i] & 0x3f);
int32 d = ((pal2[i] & 0x3f) - (pal1[i] & 0x3f));
if (d)
res = true;
int val = ((((d << 8) / targetTime) * elapsedTime) >> 8) & 0xff;
out = ((pal1[i] & 0x3f) + val) & 0xff;
int32 val = ((((d << 8) / (int32)targetTime) * (int32)elapsedTime) >> 8);
out = ((pal1[i] & 0x3f) + (int8)val);
} else {
out = p1[i] = (pal2[i] & 0x3f);
res = false;

View File

@ -70,7 +70,7 @@ public:
void loadSpecialColors(uint8 *destPalette);
void copyColor(int dstColorIndex, int srcColorIndex);
bool fadeColor(int dstColorIndex, int srcColorIndex, uint32 elapsedTime, uint32 targetTime);
bool fadePalSpecial(uint8 *pal1, uint8 *pal2, uint32 elapsedTime, uint32 targetTime);
bool fadePaletteStep(uint8 *pal1, uint8 *pal2, uint32 elapsedTime, uint32 targetTime);
void generateGrayOverlay(const uint8 *srcPal, uint8 *grayOverlay, int factor, int addR, int addG, int addB, int lastColor, bool skipSpecialColors);
uint8 *generateLevelOverlay(const uint8 *srcPal, uint8 *ovl, int opColor, int weight);

View File

@ -202,6 +202,9 @@ int LoLEngine::olol_delay(EMCState *script) {
int LoLEngine::olol_setGameFlag(EMCState *script) {
debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_setGameFlag(%p) (%d, %d)", (const void *)script, stackPos(0), stackPos(1));
assert((stackPos(0) >> 4) < 40);
if (stackPos(1))
_gameFlags[stackPos(0) >> 4] |= (1 << (stackPos(0) & 0x0f));
else
@ -215,6 +218,8 @@ int LoLEngine::olol_testGameFlag(EMCState *script) {
if (stackPos(0) < 0)
return 0;
assert((stackPos(0) >> 4) < 40);
if (_gameFlags[stackPos(0) >> 4] & (1 << (stackPos(0) & 0x0f)))
return 1;
@ -1104,6 +1109,15 @@ int LoLEngine::olol_characterJoinsParty(EMCState *script) {
return 1;
}
int LoLEngine::olol_giveItem(EMCState *script) {
debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_giveItem(%p) (%d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2));
int item = makeItem(stackPos(0), stackPos(1), stackPos(2));
if (addItemToInventory(item))
return 1;
deleteItem(item);
return 0;
}
int LoLEngine::olol_loadTimScript(EMCState *script) {
debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_loadTimScript(%p) (%d, %s)", (const void *)script, stackPos(0), stackPosString(1));
@ -1854,6 +1868,31 @@ int LoLEngine::olol_drawCharPortrait(EMCState *script) {
return 1;
}
int LoLEngine::olol_placeInventoryItemInHand(EMCState *script) {
debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_placeInventoryItemInHand(%p) (%d, %d)", (const void *)script, stackPos(0), stackPos(1));
int itemType = stackPos(0);
int i = 0;
for (; i < 48; i++) {
if (!_inventory[i])
continue;
if (_itemsInPlay[_inventory[i]].itemPropertyIndex == itemType)
break;
}
if (i == 48)
return -1;
_inventoryCurItem = i;
int r = _itemInHand;
setHandItem(_inventory[i]);
_inventory[i] = r;
if (stackPos(1))
gui_drawInventory();
return r;
}
int LoLEngine::olol_castSpell(EMCState *script) {
debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_castSpell(%p) (%d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2));
return castSpell(stackPos(0), stackPos(1), stackPos(2));
@ -2328,7 +2367,7 @@ void LoLEngine::setupOpcodeTable() {
Opcode(olol_characterJoinsParty);
// 0x4C
OpcodeUnImpl();
Opcode(olol_giveItem);
OpcodeUnImpl();
Opcode(olol_loadTimScript);
Opcode(olol_runTimScript);
@ -2472,7 +2511,7 @@ void LoLEngine::setupOpcodeTable() {
OpcodeUnImpl();
// 0xAC
OpcodeUnImpl();
Opcode(olol_placeInventoryItemInHand);
Opcode(olol_castSpell);
Opcode(olol_pitDrop);
OpcodeUnImpl();

View File

@ -1232,7 +1232,7 @@ bool LoLEngine::chasePartyWithDistanceAttacks(MonsterInPlay *monster) {
s = monster->properties->numDistWeapons ? _rnd.getRandomNumberRng(1, monster->properties->numDistWeapons) : 0;
} else {
s = monster->curDistWeapon++;
if (monster->curDistWeapon == monster->properties->numDistWeapons)
if (monster->curDistWeapon >= monster->properties->numDistWeapons)
monster->curDistWeapon = 0;
}

View File

@ -172,7 +172,7 @@ void LoLEngine::timerSpecialCharacterUpdate(int timerNum) {
break;
case 7:
level11specialUnk();
restoreSwampPalette();
break;
default: