diff options
author | johndoe123 | 2012-10-13 16:18:02 +0000 |
---|---|---|
committer | Willem Jan Palenstijn | 2013-05-08 20:47:06 +0200 |
commit | a80ec8c89c4cb102a92cf5e0fa2b2871d763486a (patch) | |
tree | 64f8fdb34f88e61374e1a9f2439981cf056b796b /engines | |
parent | b8d939a94b364a8d992a5053b527a822babccd37 (diff) | |
download | scummvm-rg350-a80ec8c89c4cb102a92cf5e0fa2b2871d763486a.tar.gz scummvm-rg350-a80ec8c89c4cb102a92cf5e0fa2b2871d763486a.tar.bz2 scummvm-rg350-a80ec8c89c4cb102a92cf5e0fa2b2871d763486a.zip |
NEVERHOOD: Implement Module2900, the teleporter
- Also fix a related bug in Module2000 (teleporter appearing animation didn't play)
Diffstat (limited to 'engines')
-rw-r--r-- | engines/neverhood/gamemodule.cpp | 58 | ||||
-rw-r--r-- | engines/neverhood/module.mk | 1 | ||||
-rw-r--r-- | engines/neverhood/module1100.cpp | 4 | ||||
-rw-r--r-- | engines/neverhood/module2000.cpp | 4 | ||||
-rw-r--r-- | engines/neverhood/module2100.h | 1 | ||||
-rw-r--r-- | engines/neverhood/module2900.cpp | 484 | ||||
-rw-r--r-- | engines/neverhood/module2900.h | 102 |
7 files changed, 648 insertions, 6 deletions
diff --git a/engines/neverhood/gamemodule.cpp b/engines/neverhood/gamemodule.cpp index a85d8a90e5..afd01f7c0a 100644 --- a/engines/neverhood/gamemodule.cpp +++ b/engines/neverhood/gamemodule.cpp @@ -42,6 +42,7 @@ #include "neverhood/module2600.h" #include "neverhood/module2700.h" #include "neverhood/module2800.h" +#include "neverhood/module2900.h" #include "neverhood/module3000.h" namespace Neverhood { @@ -358,7 +359,7 @@ void GameModule::startup() { #if 1 _vm->gameState().which = 0; _vm->gameState().sceneNum = 1; - createModule(2800, -1); + createModule(2900, 1); #endif #if 0 _vm->gameState().sceneNum = 0; @@ -499,6 +500,12 @@ void GameModule::createModule(int moduleNum, int which) { setGlobalVar(V_MODULE_NAME, 0x64210814); _childObject = new Module2800(_vm, this, which); break; + case 2900: + setGlobalVar(V_MODULE_NAME, 0x81100020); + if (which >= 0) + setGlobalVar(0x0152899A, which); + _childObject = new Module2900(_vm, this, which); + break; case 3000: setGlobalVar(V_MODULE_NAME, 0x81293110); _childObject = new Module3000(_vm, this, which); @@ -629,6 +636,55 @@ void GameModule::updateModule() { createModule(1800, 0); } break; + case 2900: + if (_moduleResult != 0xFFFFFFFF) { + switch (_moduleResult) { + case 0: + createModule(1300, 5); + break; + case 1: + createModule(2100, 1); + break; + case 2: + createModule(1100, 1); + break; + case 3: + setSubVar(0x2C145A98, 2, 1); + createModule(1700, 1); + break; + case 4: + createModule(2000, 0); + break; + case 5: + default: + createModule(2800, 1); + break; + } + } else { + switch (getGlobalVar(0x0152899A)) { + case 0: + createModule(1300, 6); + break; + case 1: + createModule(2100, 2); + break; + case 2: + createModule(1100, 2); + break; + case 3: + createModule(1700, 2); + break; + case 4: + createModule(2000, 1); + break; + case 5: + default: + createModule(2800, 2); + break; + } + } + setGlobalVar(0x0152899A, 0); + break; case 3000: if (_moduleResult == 1) { createModule(1900, 0); diff --git a/engines/neverhood/module.mk b/engines/neverhood/module.mk index 2ee28d2440..5cd41c87fe 100644 --- a/engines/neverhood/module.mk +++ b/engines/neverhood/module.mk @@ -31,6 +31,7 @@ MODULE_OBJS = \ module2600.o \ module2700.o \ module2800.o \ + module2900.o \ module3000.o \ mouse.o \ navigationscene.o \ diff --git a/engines/neverhood/module1100.cpp b/engines/neverhood/module1100.cpp index a3e092ba46..333515538a 100644 --- a/engines/neverhood/module1100.cpp +++ b/engines/neverhood/module1100.cpp @@ -44,9 +44,9 @@ Module1100::Module1100(NeverhoodEngine *vm, Module *parentModule, int which) if (which < 0) { createScene(_vm->gameState().sceneNum, -1); } else if (which == 1) { - createScene(9, 1); + createScene(8, 1); } else { - createScene(9, 3); + createScene(8, 3); } _vm->_soundMan->addSoundList(0x0002C818, kModule1100SoundList); diff --git a/engines/neverhood/module2000.cpp b/engines/neverhood/module2000.cpp index befcc3414a..75a6ebe899 100644 --- a/engines/neverhood/module2000.cpp +++ b/engines/neverhood/module2000.cpp @@ -32,9 +32,9 @@ Module2000::Module2000(NeverhoodEngine *vm, Module *parentModule, int which) if (which < 0) { createScene(_vm->gameState().sceneNum, -1); } else if (which == 0) { - createScene(0, 3); - } else if (which == 1) { createScene(0, 1); + } else if (which == 1) { + createScene(0, 3); } } diff --git a/engines/neverhood/module2100.h b/engines/neverhood/module2100.h index 4690913cb3..cf7a613cbf 100644 --- a/engines/neverhood/module2100.h +++ b/engines/neverhood/module2100.h @@ -71,7 +71,6 @@ protected: uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); }; - class Scene2101 : public Scene { public: Scene2101(NeverhoodEngine *vm, Module *parentModule, int which); diff --git a/engines/neverhood/module2900.cpp b/engines/neverhood/module2900.cpp new file mode 100644 index 0000000000..2ebdb094a3 --- /dev/null +++ b/engines/neverhood/module2900.cpp @@ -0,0 +1,484 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "neverhood/module2900.h" +#include "neverhood/gamemodule.h" +#include "neverhood/module1100.h" +#include "neverhood/module1300.h" +#include "neverhood/module1700.h" +#include "neverhood/module2000.h" +#include "neverhood/module2100.h" +#include "neverhood/module2800.h" + +namespace Neverhood { + +Module2900::Module2900(NeverhoodEngine *vm, Module *parentModule, int which) + : Module(vm, parentModule) { + + if (which >= 0) + setGlobalVar(0x60826830, which); + + createScene(0, 0); + +} + +void Module2900::createScene(int sceneNum, int which) { + debug("Module2900::createScene(%d, %d)", sceneNum, which); + _sceneNum = sceneNum; + switch (_sceneNum) { + case 0: + _vm->gameState().sceneNum = 0; + _childObject = new Scene2901(_vm, this, getGlobalVar(0x60826830)); + break; + case 1: + _vm->gameState().sceneNum = 0; + _childObject = new Scene2805(_vm, this, which); + break; + case 2: + _vm->gameState().sceneNum = 0; + _childObject = new Scene2101(_vm, this, which); + break; + case 3: + _vm->gameState().sceneNum = 0; + _childObject = new Scene1306(_vm, this, which); + break; + case 4: + _vm->gameState().sceneNum = 0; + _childObject = new Scene1705(_vm, this, which); + break; + case 5: + _vm->gameState().sceneNum = 0; + _childObject = new Scene1109(_vm, this, which); + break; + case 6: + _vm->gameState().sceneNum = 0; + _childObject = new Scene2001(_vm, this, which); + break; + } + SetUpdateHandler(&Module2900::updateScene); + _childObject->handleUpdate(); +} + +void Module2900::updateScene() { + if (!updateChild()) { + switch (_sceneNum) { + case 0: + if (_moduleResult == 0xFFFFFFFF) { + leaveModule(0xFFFFFFFF); + } else { + _field2C = _moduleResult; + switch (getGlobalVar(0x60826830)) { + case 0: + createScene(3, 4); + break; + case 1: + createScene(2, 2); + break; + case 2: + createScene(5, 2); + break; + case 3: + createScene(4, 2); + break; + case 4: + createScene(6, 2); + break; + case 5: + createScene(1, 2); + break; + default: + leaveModule(_moduleResult); + break; + } + } + break; + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + leaveModule(_field2C); + break; + } + } +} + +static const uint32 kScene2901FileHashes1[] = { + 0x023023B4, + 0x36204507, + 0x046CF08E, + 0x9313A237, + 0xA651F246, + 0x02108034 +}; + +static const uint32 kScene2901FileHashes2[] = { + 0x023B002B, + 0x0450336A, + 0xCF08A04E, + 0x3A233939, + 0x1F242A6D, + 0x08030029 +}; + +static const uint32 kSsScene2901LocationButtonFileHashes[] = { + 0x2311326A, + 0x212323AC, + 0x10098138, + 0x25213167, + 0x1119A363, + 0x94452612, + 0x39464212, + 0x01860450, + 0x53002104, + 0x58E68412, + 0x18600300, + 0xB650A890, + 0x2452A7C4, + 0xA0232748, + 0x08862B02, + 0x2491E648, + 0x0010EB46, + 0x214C8A11, + 0x16A31921, + 0x0AC33A00, + 0x238028AA, + 0x26737A21, + 0x063039A8, + 0x51286C60, + 0x464006B4, + 0x42242538, + 0x20716010, + 0x4A2000AE, + 0x225124A6, + 0x28E82E45, + 0x58652C04, + 0xC82210A4, + 0x62A84060, + 0xC0693CB4, + 0x22212C64, + 0x5034EA71 +}; + +static const NPoint kSsScene2901LocationButtonPoints[] = { + {525, 120}, {576, 149}, {587, 205}, + {538, 232}, {484, 205}, {479, 153} +}; + +static const uint32 kSsScene2901LocationButtonLightFileHashes1[] = { + 0x03136246, + 0x2106216E, + 0x4025A13A, + 0x21816927, + 0x110B2202, + 0xCC0522B2, + 0x3CC24258, + 0x59C600F0, + 0x534A2480, + 0x50E61019, + 0x34400150, + 0x225BA090, + 0xB059AFC4, + 0xE093A741, + 0x0086BF09, + 0x3281E760, + 0xA048AB42, + 0x20649C01, + 0x14611904, + 0x26E33850, + 0x23A52A68, + 0xA2733024, + 0x10203880, + 0x1B2DE860, + 0x0644A6EC, + 0x426E20BC, + 0x80292014, + 0x4360B02E, + 0x22742664, + 0x98682705, + 0x0925B82C, + 0x5C2918A4, + 0xD2284920, + 0x41083CA6, + 0x6824A864, + 0x50266B10 +}; + +static const uint32 kSsScene2901LocationButtonLightFileHashes2[] = { + 0x43C46D4C, + 0x43C4AD4C, + 0x43C52D4C, + 0x43C62D4C, + 0x43C02D4C, + 0x43CC2D4C +}; + +static const uint32 kSsScene2901BrokenButtonFileHashes[] = { + 0x3081BD3A, + 0xD3443003, + 0x0786A320, + 0xE3A22029, + 0x61611814, + 0x425848E2 +}; + +static const uint32 kSsScene2901BigButtonFileHashes[] = { + 0x010D7748, + 0x9D02019A, + 0x351A2F43, + 0x448138E5, + 0x02788CF0, + 0x71718024 +}; + +SsScene2901LocationButton::SsScene2901LocationButton(NeverhoodEngine *vm, Scene *parentScene, int which, uint index) + : StaticSprite(vm, 900), _parentScene(parentScene), _index(index), _countdown1(0) { + + _spriteResource.load2(kSsScene2901LocationButtonFileHashes[which * 6 + index]); + createSurface(800, _spriteResource.getDimensions().width, _spriteResource.getDimensions().height); + _drawRect.x = 0; + _drawRect.y = 0; + _drawRect.width = _spriteResource.getDimensions().width; + _drawRect.height = _spriteResource.getDimensions().height; + _x = _spriteResource.getPosition().x; + _y = _spriteResource.getPosition().y; + _rect.x1 = kSsScene2901LocationButtonPoints[_index].x - 25; + _rect.y1 = kSsScene2901LocationButtonPoints[_index].y - 25; + _rect.x2 = kSsScene2901LocationButtonPoints[_index].x + 25; + _rect.y2 = kSsScene2901LocationButtonPoints[_index].y + 25; + setVisible(false); + _needRefresh = true; + loadSound(0, 0x440430C0); + SetUpdateHandler(&SsScene2901LocationButton::update); + SetMessageHandler(&SsScene2901LocationButton::handleMessage); +} + +void SsScene2901LocationButton::update() { + StaticSprite::update(); + if (_countdown1 != 0 && (--_countdown1) == 0) { + setVisible(false); + } +} + +uint32 SsScene2901LocationButton::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { + uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); + switch (messageNum) { + case 0x1011: + if (_countdown1 == 0) { + playSound(0); + setVisible(true); + _countdown1 = 4; + sendMessage(_parentScene, 0x2001, _index); + } + messageResult = 1; + break; + } + return messageResult; +} + +SsScene2901LocationButtonLight::SsScene2901LocationButtonLight(NeverhoodEngine *vm, int which, uint index) + : StaticSprite(vm, 900), _index(index) { + + _spriteResource.load2(kSsScene2901LocationButtonLightFileHashes1[which * 6 + index]); + createSurface(900, _spriteResource.getDimensions().width, _spriteResource.getDimensions().height); + _drawRect.x = 0; + _drawRect.y = 0; + _drawRect.width = _spriteResource.getDimensions().width; + _drawRect.height = _spriteResource.getDimensions().height; + _x = _spriteResource.getPosition().x; + _y = _spriteResource.getPosition().y; + setVisible(false); + _needRefresh = true; + loadSound(0, kSsScene2901LocationButtonLightFileHashes2[_index]); +} + +void SsScene2901LocationButtonLight::show() { + playSound(0); + setVisible(true); + StaticSprite::update(); +} + +void SsScene2901LocationButtonLight::hide() { + setVisible(false); + StaticSprite::update(); +} + +SsScene2901BrokenButton::SsScene2901BrokenButton(NeverhoodEngine *vm, int which) + : StaticSprite(vm, 900) { + + _spriteResource.load2(kSsScene2901BrokenButtonFileHashes[which]); + createSurface(900, _spriteResource.getDimensions().width, _spriteResource.getDimensions().height); + _drawRect.x = 0; + _drawRect.y = 0; + _drawRect.width = _spriteResource.getDimensions().width; + _drawRect.height = _spriteResource.getDimensions().height; + _x = _spriteResource.getPosition().x; + _y = _spriteResource.getPosition().y; + _needRefresh = true; + StaticSprite::update(); +} + +SsScene2901BigButton::SsScene2901BigButton(NeverhoodEngine *vm, Scene *parentScene, int which) + : StaticSprite(vm, 900), _parentScene(parentScene), _which(which), _countdown1(0) { + + _spriteResource.load2(kSsScene2901BigButtonFileHashes[which]); + createSurface(400, _spriteResource.getDimensions().width, _spriteResource.getDimensions().height); + _drawRect.x = 0; + _drawRect.y = 0; + _drawRect.width = _spriteResource.getDimensions().width; + _drawRect.height = _spriteResource.getDimensions().height; + _x = _spriteResource.getPosition().x; + _y = _spriteResource.getPosition().y; + _rect.x1 = 62; + _rect.y1 = 94; + _rect.x2 = 322; + _rect.y2 = 350; + setVisible(false); + _needRefresh = true; + loadSound(0, 0xF3D420C8); + SetUpdateHandler(&SsScene2901BigButton::update); + SetMessageHandler(&SsScene2901BigButton::handleMessage); +} + +void SsScene2901BigButton::update() { + StaticSprite::update(); + if (_countdown1 != 0 && (--_countdown1) == 0) { + setVisible(false); + sendMessage(_parentScene, 0x2000, 0); + } +} + +uint32 SsScene2901BigButton::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { + uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); + switch (messageNum) { + case 0x1011: + if (_countdown1 == 0) { + playSound(0); + setVisible(true); + _countdown1 = 4; + } + messageResult = 1; + break; + } + return messageResult; +} + +Scene2901::Scene2901(NeverhoodEngine *vm, Module *parentModule, int which) + : Scene(vm, parentModule, true), _currLocationButtonNum(which), _selectedButtonNum(which), + _currWhirlButtonNum(0), _prevWhirlButtonNum(0), _countdown1(1), _skipCountdown(0), _blinkOn(0) { + + _isButton2Broken = getGlobalVar(V_ENTRANCE_OPEN) != 0; + + //DEBUG>>> Enable all locations + for (int i = 0; i < 6; i++) + setSubVar(0x2C145A98, i, 1); + //DEBUG<<< + + setSubVar(0x2C145A98, which, 1); + setSubVar(0x2C145A98, 5, 1); + setSubVar(0x2C145A98, 4, 1); + + if (_currLocationButtonNum == 3) + setSubVar(0x2C145A98, 2, 1); + + _surfaceFlag = true; + setBackground(kScene2901FileHashes1[_currLocationButtonNum]); + setPalette(kScene2901FileHashes1[_currLocationButtonNum]); + + for (uint i = 0; i < 6; ++i) { + if (i != 2 || !_isButton2Broken) { + _ssLocationButtons[i] = insertSprite<SsScene2901LocationButton>(this, _currLocationButtonNum, i); + _vm->_collisionMan->addSprite(_ssLocationButtons[i]); + _ssLocationButtonLights[i] = insertSprite<SsScene2901LocationButtonLight>(_currLocationButtonNum, i); + } + } + + if (_isButton2Broken) + insertSprite<SsScene2901BrokenButton>(_currLocationButtonNum); + + _ssBigButton = insertSprite<SsScene2901BigButton>(this, _currLocationButtonNum); + _vm->_collisionMan->addSprite(_ssBigButton); + + insertMouse435(kScene2901FileHashes2[_currLocationButtonNum], 20, 620); + + SetUpdateHandler(&Scene2901::update); + SetMessageHandler(&Scene2901::handleMessage); + +} + +void Scene2901::update() { + Scene::update(); + if (_countdown1 != 0 && (--_countdown1) == 0) { + if (_currLocationButtonNum == _selectedButtonNum) { + _ssLocationButtonLights[_currWhirlButtonNum]->hide(); + ++_currWhirlButtonNum; + while (!getSubVar(0x2C145A98, _currWhirlButtonNum) || (_currWhirlButtonNum == 2 && _isButton2Broken) || _currLocationButtonNum == _currWhirlButtonNum) { + ++_currWhirlButtonNum; + if (_currWhirlButtonNum >= 6) + _currWhirlButtonNum = 0; + } + if (_currWhirlButtonNum != _prevWhirlButtonNum || _skipCountdown == 0) { + _ssLocationButtonLights[_currWhirlButtonNum]->show(); + _skipCountdown = 4; + } + _countdown1 = 2; + --_skipCountdown; + _prevWhirlButtonNum = _currWhirlButtonNum; + } else if (_blinkOn) { + _blinkOn = false; + _ssLocationButtonLights[_selectedButtonNum]->hide(); + _countdown1 = 16; + } else { + _blinkOn = true; + _ssLocationButtonLights[_selectedButtonNum]->show(); + _countdown1 = 4; + } + } +} + +uint32 Scene2901::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { + Scene::handleMessage(messageNum, param, sender); + switch (messageNum) { + case 0x0001: + if (param.asPoint().x <= 20 || param.asPoint().x >= 620) { + leaveScene(0xFFFFFFFF); + } + break; + case 0x2000: + if (_currLocationButtonNum != _selectedButtonNum) { + leaveScene(_selectedButtonNum); + } + break; + case 0x2001: + if (_currLocationButtonNum == _selectedButtonNum) + _selectedButtonNum = _currWhirlButtonNum; + _ssLocationButtonLights[_selectedButtonNum]->hide(); + _selectedButtonNum = param.asInteger(); + if (!getSubVar(0x2C145A98, _selectedButtonNum)) + _selectedButtonNum = _currLocationButtonNum; + break; + } + return 0; +} + +} // End of namespace Neverhood diff --git a/engines/neverhood/module2900.h b/engines/neverhood/module2900.h new file mode 100644 index 0000000000..7d4e1e4d9f --- /dev/null +++ b/engines/neverhood/module2900.h @@ -0,0 +1,102 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef NEVERHOOD_MODULE2900_H +#define NEVERHOOD_MODULE2900_H + +#include "neverhood/neverhood.h" +#include "neverhood/module.h" +#include "neverhood/scene.h" + +namespace Neverhood { + +// Module2900 + +class Module2900 : public Module { +public: + Module2900(NeverhoodEngine *vm, Module *parentModule, int which); +protected: + int _sceneNum; + int _field2C; + void createScene(int sceneNum, int which); + void updateScene(); + void updateMusic(bool halfVolume); +}; + +class SsScene2901LocationButton : public StaticSprite { +public: + SsScene2901LocationButton(NeverhoodEngine *vm, Scene *parentScene, int which, uint index); +protected: + Scene *_parentScene; + uint _index; + int _countdown1; + void update(); + uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); +}; + +class SsScene2901LocationButtonLight : public StaticSprite { +public: + SsScene2901LocationButtonLight(NeverhoodEngine *vm, int which, uint index); + void show(); + void hide(); +protected: + uint _index; +}; + +class SsScene2901BrokenButton : public StaticSprite { +public: + SsScene2901BrokenButton(NeverhoodEngine *vm, int which); +}; + +class SsScene2901BigButton : public StaticSprite { +public: + SsScene2901BigButton(NeverhoodEngine *vm, Scene *parentScene, int which); +protected: + Scene *_parentScene; + int _which; + int _countdown1; + void update(); + uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); +}; + +class Scene2901 : public Scene { +public: + Scene2901(NeverhoodEngine *vm, Module *parentModule, int which); +protected: + Sprite *_ssLocationButtons[6]; + SsScene2901LocationButtonLight *_ssLocationButtonLights[6]; + Sprite *_ssBigButton; + int _currWhirlButtonNum; + int _prevWhirlButtonNum; + int _countdown1; + int _currLocationButtonNum; + int _selectedButtonNum; + int _skipCountdown; + int _blinkOn; + bool _isButton2Broken; + void update(); + uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); +}; + +} // End of namespace Neverhood + +#endif /* NEVERHOOD_MODULE2900_H */ |