diff options
author | johndoe123 | 2015-12-15 13:34:08 +0100 |
---|---|---|
committer | Eugene Sandulenko | 2018-07-20 06:43:33 +0000 |
commit | 6b80f5b85349fc2bd645da52c4e68a337894f38a (patch) | |
tree | 5e2e0f1165dfad8b6e2c9da012ea60e4082d6823 | |
parent | c9b0a8452a3c5ef64da2955ef58412efa32e70c4 (diff) | |
download | scummvm-rg350-6b80f5b85349fc2bd645da52c4e68a337894f38a.tar.gz scummvm-rg350-6b80f5b85349fc2bd645da52c4e68a337894f38a.tar.bz2 scummvm-rg350-6b80f5b85349fc2bd645da52c4e68a337894f38a.zip |
ILLUSIONS: DUCKMAN: Move game credits into own file and class
-rw-r--r-- | engines/illusions/duckman/duckman_credits.cpp | 198 | ||||
-rw-r--r-- | engines/illusions/duckman/duckman_credits.h | 62 | ||||
-rw-r--r-- | engines/illusions/duckman/duckman_specialcode.cpp | 157 | ||||
-rw-r--r-- | engines/illusions/duckman/duckman_specialcode.h | 16 | ||||
-rw-r--r-- | engines/illusions/duckman/scriptopcodes_duckman.cpp | 4 | ||||
-rw-r--r-- | engines/illusions/module.mk | 1 |
6 files changed, 270 insertions, 168 deletions
diff --git a/engines/illusions/duckman/duckman_credits.cpp b/engines/illusions/duckman/duckman_credits.cpp new file mode 100644 index 0000000000..18a0482ae4 --- /dev/null +++ b/engines/illusions/duckman/duckman_credits.cpp @@ -0,0 +1,198 @@ +/* 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 "illusions/duckman/illusions_duckman.h" +#include "illusions/duckman/duckman_credits.h" +#include "illusions/actor.h" +#include "illusions/dictionary.h" +#include "illusions/resources/fontresource.h" +#include "illusions/resources/scriptresource.h" +#include "illusions/textdrawer.h" +#include "illusions/time.h" +#include "illusions/updatefunctions.h" + +#include "engines/util.h" + +namespace Illusions { + +// Duckman_SpecialCode + +DuckmanCredits::DuckmanCredits(IllusionsEngine_Duckman *vm) + : _vm(vm) { + +} + +DuckmanCredits::~DuckmanCredits() { +} + +void DuckmanCredits::start() { + static const struct { uint32 objectId; int scrollPosY; } kCreditsItems[] = { + {0x40136, 0}, {0x40137, 16}, {0x40138, 32}, {0x40139, 48}, + {0x4013A, 64}, {0x4013B, 80}, {0x4013C, 96}, {0x4013D, 112} + }; + _currText = (char*)_vm->_resSys->getResource(0x190052)->_data; + _creditsItems.clear(); + for (uint i = 0; i < ARRAYSIZE(kCreditsItems); ++i) { + CreditsItem creditsItem; + creditsItem.objectId = kCreditsItems[i].objectId; + creditsItem.scrollPosY = kCreditsItems[i].scrollPosY; + creditsItem.scrollPosIndex = 0; + creditsItem.active = false; + _creditsItems.push_back(creditsItem); + } + uint32 currSceneId = _vm->getCurrentScene(); + _vm->_updateFunctions->add(0, currSceneId, new Common::Functor1Mem<uint, int, DuckmanCredits>(this, &DuckmanCredits::update)); + _nextUpdateTicks = getCurrentTime(); + _lastUpdateTicks = _nextUpdateTicks - 4; +} + +int DuckmanCredits::update(uint flags) { + + if (_vm->_pauseCtr > 0) { + _nextUpdateTicks = getCurrentTime() + 4; + return 1; + } + + if (flags & 1) { + _vm->_scriptResource->_properties.set(0x000E0096, true); + _lastItemIndex = -1; + _endReached = false; + return 2; + } + + if (!isTimerExpired(_lastUpdateTicks, _nextUpdateTicks)) { + return 1; + } + + bool creditsRunning = false; + int index = 0; + for (CreditsItems::iterator it = _creditsItems.begin(); it != _creditsItems.end(); ++it, ++index) { + CreditsItem &creditsItem = *it; + Control *control = _vm->getObjectControl(creditsItem.objectId); + if (!creditsItem.active && creditsItem.scrollPosY == 0 && !_endReached) { + creditsItem.active = true; + creditsItem.scrollPosIndex = 0; + control->fillActor(0); + char *text = readNextLine(); + if (!strncmp(text, "&&&END", 6)) { + creditsItem.active = false; + _endReached = true; + } else { + uint16 wtext[128]; + charToWChar(text, wtext, ARRAYSIZE(wtext)); + + FontResource *font = _vm->_dict->findFont(0x120001); + TextDrawer textDrawer; + WidthHeight dimensions; + uint16 *outText; + control->getActorFrameDimensions(dimensions); + textDrawer.wrapText(font, wtext, &dimensions, Common::Point(0, 0), 2, outText); + textDrawer.drawText(_vm->_screen, control->_actor->_surface, 0, 0); + control->_actor->_flags |= 0x4000; + + _lastItemIndex = index; + } + } + if (creditsItem.active) { + if (_endReached && _creditsItems[_lastItemIndex].scrollPosIndex > 53) { + creditsItem.active = false; + creditsItem.scrollPosY = -1; + } else { + creditsRunning = true; + control->_actor->_position = getItemPosition(creditsItem.scrollPosIndex); + ++creditsItem.scrollPosIndex; + if (getItemPosition(creditsItem.scrollPosIndex).x < 0) + creditsItem.active = false; + } + } + if (creditsItem.scrollPosY > 0) + --creditsItem.scrollPosY; + } + _lastUpdateTicks = _nextUpdateTicks; + _nextUpdateTicks = getCurrentTime() + 4; + + if (!creditsRunning) { + _vm->_scriptResource->_properties.set(0x000E0096, true); + _lastItemIndex = -1; + _endReached = false; + return 2; + } + + return 1; +} + +char *DuckmanCredits::readNextLine() { + static char line[256]; + char *dest = line; + char *src = _currText; + do { + if (*src == 10 || *src == 13) { + src += 2; + *dest = 0; + break; + } + *dest++ = *src++; + } while (1); + _currText = src; + return line; +} + +Common::Point DuckmanCredits::getItemPosition(int index) { + static const struct { int16 x, y; } kCreditsItemsPoints[] = { + {159, 200}, {158, 195}, {157, 190}, {156, 185}, {156, 180}, {157, 176}, + {158, 172}, {159, 168}, {161, 164}, {162, 161}, {163, 158}, {163, 155}, + {162, 152}, {161, 149}, {159, 147}, {158, 144}, {157, 142}, {156, 140}, + {156, 138}, {157, 136}, {158, 134}, {159, 132}, {161, 130}, {162, 128}, + {163, 127}, {163, 126}, {162, 125}, {161, 124}, {159, 123}, {158, 122}, + {157, 121}, {156, 120}, {156, 119}, {157, 118}, {158, 117}, {159, 116}, + {161, 115}, {162, 114}, {163, 113}, {163, 112}, {162, 111}, {161, 110}, + {159, 109}, {158, 108}, {157, 107}, {156, 106}, {156, 105}, {157, 104}, + {158, 103}, {159, 102}, {161, 101}, {162, 100}, {163, 99}, {163, 98}, + {162, 97}, {161, 96}, {159, 95}, {158, 94}, {157, 93}, {156, 92}, + {156, 91}, {157, 90}, {158, 89}, {159, 88}, {161, 87}, {162, 86}, + {163, 85}, {163, 84}, {162, 83}, {161, 82}, {159, 81}, {158, 80}, + {157, 79}, {156, 78}, {156, 77}, {157, 76}, {158, 75}, {159, 74}, + {161, 73}, {162, 72}, {163, 71}, {163, 70}, {162, 69}, {161, 68}, + {159, 67}, {158, 66}, {157, 64}, {156, 62}, {156, 60}, {157, 58}, + {158, 56}, {159, 54}, {161, 52}, {162, 50}, {163, 40}, {163, 40}, + {162, 40}, {161, 40}, {159, 40}, {158, 40}, {157, 40}, {156, 40}, + {156, 40}, {157, 40}, {158, 40}, {159, 40}, {161, 40}, {162, 40}, + {163, 40}, {163, 40}, {162, 40}, {161, 40}, {159, 40}, {158, 40}, + {157, 40}, {156, 40}, {156, 40}, {157, 40}, {158, 40}, {159, 40}, + {161, 40}, {162, 40}, {163, 40}, {163, 40}, {162, 40}, {161, 40}, + {159, 40}, {158, 40}, { -1, -1} + }; + + if (index < 0 || index >= ARRAYSIZE(kCreditsItemsPoints)) + return Common::Point(-1, -1); + return Common::Point(kCreditsItemsPoints[index].x, kCreditsItemsPoints[index].y); +} + +void DuckmanCredits::charToWChar(char *text, uint16 *wtext, uint size) { + while (*text != 0 && size > 1) { + *wtext++ = (byte)*text++; + --size; + } + *wtext++ = 0; +} + +} // End of namespace Illusions diff --git a/engines/illusions/duckman/duckman_credits.h b/engines/illusions/duckman/duckman_credits.h new file mode 100644 index 0000000000..039575ced5 --- /dev/null +++ b/engines/illusions/duckman/duckman_credits.h @@ -0,0 +1,62 @@ +/* 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 ILLUSIONS_DUCKMAN_CREDITS_H +#define ILLUSIONS_DUCKMAN_CREDITS_H + +#include "illusions/illusions.h" + +namespace Illusions { + +class IllusionsEngine_Duckman; + +struct CreditsItem { + uint32 objectId; + bool active; + int16 scrollPosIndex; + int16 scrollPosY; +}; + +class DuckmanCredits { +public: + DuckmanCredits(IllusionsEngine_Duckman *vm); + ~DuckmanCredits(); + void start(); +public: + typedef Common::Array<CreditsItem> CreditsItems; + IllusionsEngine_Duckman *_vm; + uint32 _lastUpdateTicks; + uint32 _nextUpdateTicks; + int _lastItemIndex; + bool _endReached; + CreditsItems _creditsItems; + char *_currText; + int update(uint flags); + char *readNextLine(); + Common::Point getItemPosition(int index); + void charToWChar(char *text, uint16 *wtext, uint size); + +}; + +} // End of namespace Illusions + +#endif // ILLUSIONS_ILLUSIONS_H diff --git a/engines/illusions/duckman/duckman_specialcode.cpp b/engines/illusions/duckman/duckman_specialcode.cpp index f0c3698520..d53896d6ac 100644 --- a/engines/illusions/duckman/duckman_specialcode.cpp +++ b/engines/illusions/duckman/duckman_specialcode.cpp @@ -21,6 +21,7 @@ */ #include "illusions/duckman/illusions_duckman.h" +#include "illusions/duckman/duckman_credits.h" #include "illusions/duckman/duckman_screenshakereffects.h" #include "illusions/duckman/duckman_specialcode.h" #include "illusions/duckman/duckman_inventory.h" @@ -47,6 +48,8 @@ DuckmanSpecialCode::DuckmanSpecialCode(IllusionsEngine_Duckman *vm) _propertyTimers = new PropertyTimers(_vm); _inventory = new DuckmanInventory(_vm); + _credits = new DuckmanCredits(_vm); + _wasCursorHoldingElvisPoster = false; _counter = 0; _savedTempMasterSfxVolume = 16; @@ -56,6 +59,7 @@ DuckmanSpecialCode::DuckmanSpecialCode(IllusionsEngine_Duckman *vm) DuckmanSpecialCode::~DuckmanSpecialCode() { delete _propertyTimers; delete _inventory; + delete _credits; } typedef Common::Functor1Mem<OpCall&, void, DuckmanSpecialCode> SpecialCodeFunctionDM; @@ -339,7 +343,7 @@ void DuckmanSpecialCode::spcHoldGlowingElvisPoster(OpCall &opCall) { void DuckmanSpecialCode::spcStartCredits(OpCall &opCall) { ARG_BYTE(mode); if (mode == 0) - startCredits(); + _credits->start(); _vm->notifyThreadId(opCall._threadId); } @@ -391,155 +395,4 @@ void DuckmanSpecialCode::updateTeleporterProperties() { _vm->_scriptResource->_properties.set(0x000E0078, _teleporterPosition.x == 1 && _teleporterPosition.y == 1); } -void DuckmanSpecialCode::startCredits() { - static const struct { uint32 objectId; int scrollPosY; } kCreditsItems[] = { - {0x40136, 0}, {0x40137, 16}, {0x40138, 32}, {0x40139, 48}, - {0x4013A, 64}, {0x4013B, 80}, {0x4013C, 96}, {0x4013D, 112} - }; - _creditsCurrText = (char*)_vm->_resSys->getResource(0x190052)->_data; - _creditsItems.clear(); - for (uint i = 0; i < ARRAYSIZE(kCreditsItems); ++i) { - CreditsItem creditsItem; - creditsItem.objectId = kCreditsItems[i].objectId; - creditsItem.scrollPosY = kCreditsItems[i].scrollPosY; - creditsItem.scrollPosIndex = 0; - creditsItem.active = false; - _creditsItems.push_back(creditsItem); - } - uint32 currSceneId = _vm->getCurrentScene(); - _vm->_updateFunctions->add(0, currSceneId, new Common::Functor1Mem<uint, int, DuckmanSpecialCode>(this, &DuckmanSpecialCode::updateCredits)); - _creditsNextUpdateTicks = getCurrentTime(); - _creditsLastUpdateTicks = _creditsNextUpdateTicks - 4; -} - -int DuckmanSpecialCode::updateCredits(uint flags) { - - if (_vm->_pauseCtr > 0) { - _creditsNextUpdateTicks = getCurrentTime() + 4; - return 1; - } - - if (flags & 1) { - _vm->_scriptResource->_properties.set(0x000E0096, true); - _lastCreditsItemIndex = -1; - _creditsEndReached = false; - return 2; - } - - if (!isTimerExpired(_creditsLastUpdateTicks, _creditsNextUpdateTicks)) { - return 1; - } - - bool creditsRunning = false; - int index = 0; - for (CreditsItems::iterator it = _creditsItems.begin(); it != _creditsItems.end(); ++it, ++index) { - CreditsItem &creditsItem = *it; - Control *control = _vm->getObjectControl(creditsItem.objectId); - if (!creditsItem.active && creditsItem.scrollPosY == 0 && !_creditsEndReached) { - creditsItem.active = true; - creditsItem.scrollPosIndex = 0; - control->fillActor(0); - char *text = readNextCreditsLine(); - if (!strncmp(text, "&&&END", 6)) { - creditsItem.active = false; - _creditsEndReached = true; - } else { - uint16 wtext[128]; - charToWChar(text, wtext, ARRAYSIZE(wtext)); - - FontResource *font = _vm->_dict->findFont(0x120001); - TextDrawer textDrawer; - WidthHeight dimensions; - uint16 *outText; - control->getActorFrameDimensions(dimensions); - textDrawer.wrapText(font, wtext, &dimensions, Common::Point(0, 0), 2, outText); - textDrawer.drawText(_vm->_screen, control->_actor->_surface, 0, 0); - control->_actor->_flags |= 0x4000; - - _lastCreditsItemIndex = index; - } - } - if (creditsItem.active) { - if (_creditsEndReached && _creditsItems[_lastCreditsItemIndex].scrollPosIndex > 53) { - creditsItem.active = false; - creditsItem.scrollPosY = -1; - } else { - creditsRunning = true; - control->_actor->_position = getCreditsItemPosition(creditsItem.scrollPosIndex); - ++creditsItem.scrollPosIndex; - if (getCreditsItemPosition(creditsItem.scrollPosIndex).x < 0) - creditsItem.active = false; - } - } - if (creditsItem.scrollPosY > 0) - --creditsItem.scrollPosY; - } - _creditsLastUpdateTicks = _creditsNextUpdateTicks; - _creditsNextUpdateTicks = getCurrentTime() + 4; - - if (!creditsRunning) { - _vm->_scriptResource->_properties.set(0x000E0096, true); - _lastCreditsItemIndex = -1; - _creditsEndReached = false; - return 2; - } - - return 1; -} - -char *DuckmanSpecialCode::readNextCreditsLine() { - static char line[256]; - char *dest = line; - char *src = _creditsCurrText; - do { - if (*src == 10 || *src == 13) { - src += 2; - *dest = 0; - break; - } - *dest++ = *src++; - } while (1); - _creditsCurrText = src; - return line; -} - -Common::Point DuckmanSpecialCode::getCreditsItemPosition(int index) { - static const struct { int16 x, y; } kCreditsItemsPoints[] = { - {159, 200}, {158, 195}, {157, 190}, {156, 185}, {156, 180}, {157, 176}, - {158, 172}, {159, 168}, {161, 164}, {162, 161}, {163, 158}, {163, 155}, - {162, 152}, {161, 149}, {159, 147}, {158, 144}, {157, 142}, {156, 140}, - {156, 138}, {157, 136}, {158, 134}, {159, 132}, {161, 130}, {162, 128}, - {163, 127}, {163, 126}, {162, 125}, {161, 124}, {159, 123}, {158, 122}, - {157, 121}, {156, 120}, {156, 119}, {157, 118}, {158, 117}, {159, 116}, - {161, 115}, {162, 114}, {163, 113}, {163, 112}, {162, 111}, {161, 110}, - {159, 109}, {158, 108}, {157, 107}, {156, 106}, {156, 105}, {157, 104}, - {158, 103}, {159, 102}, {161, 101}, {162, 100}, {163, 99}, {163, 98}, - {162, 97}, {161, 96}, {159, 95}, {158, 94}, {157, 93}, {156, 92}, - {156, 91}, {157, 90}, {158, 89}, {159, 88}, {161, 87}, {162, 86}, - {163, 85}, {163, 84}, {162, 83}, {161, 82}, {159, 81}, {158, 80}, - {157, 79}, {156, 78}, {156, 77}, {157, 76}, {158, 75}, {159, 74}, - {161, 73}, {162, 72}, {163, 71}, {163, 70}, {162, 69}, {161, 68}, - {159, 67}, {158, 66}, {157, 64}, {156, 62}, {156, 60}, {157, 58}, - {158, 56}, {159, 54}, {161, 52}, {162, 50}, {163, 40}, {163, 40}, - {162, 40}, {161, 40}, {159, 40}, {158, 40}, {157, 40}, {156, 40}, - {156, 40}, {157, 40}, {158, 40}, {159, 40}, {161, 40}, {162, 40}, - {163, 40}, {163, 40}, {162, 40}, {161, 40}, {159, 40}, {158, 40}, - {157, 40}, {156, 40}, {156, 40}, {157, 40}, {158, 40}, {159, 40}, - {161, 40}, {162, 40}, {163, 40}, {163, 40}, {162, 40}, {161, 40}, - {159, 40}, {158, 40}, { -1, -1} - }; - - if (index < 0 || index >= ARRAYSIZE(kCreditsItemsPoints)) - return Common::Point(-1, -1); - return Common::Point(kCreditsItemsPoints[index].x, kCreditsItemsPoints[index].y); -} - -void DuckmanSpecialCode::charToWChar(char *text, uint16 *wtext, uint size) { - while (*text != 0 && size > 1) { - *wtext++ = (byte)*text++; - --size; - } - *wtext++ = 0; -} - } // End of namespace Illusions diff --git a/engines/illusions/duckman/duckman_specialcode.h b/engines/illusions/duckman/duckman_specialcode.h index 9176a643b0..a9fb7b9803 100644 --- a/engines/illusions/duckman/duckman_specialcode.h +++ b/engines/illusions/duckman/duckman_specialcode.h @@ -30,18 +30,12 @@ namespace Illusions { class IllusionsEngine_Duckman; +class DuckmanCredits; class DuckmanInventory; class PropertyTimers; typedef Common::Functor1<OpCall&, void> SpecialCodeFunction; -struct CreditsItem { - uint32 objectId; - bool active; - int16 scrollPosIndex; - int16 scrollPosY; -}; - class DuckmanSpecialCode : public SpecialCode { public: DuckmanSpecialCode(IllusionsEngine_Duckman *vm); @@ -51,7 +45,6 @@ public: public: typedef Common::HashMap<uint32, SpecialCodeFunction*> SpecialCodeMap; typedef SpecialCodeMap::iterator SpecialCodeMapIterator; - typedef Common::Array<CreditsItem> CreditsItems; IllusionsEngine_Duckman *_vm; SpecialCodeMap _specialCodeMap; @@ -67,12 +60,7 @@ public: int16 _savedTempMasterSfxVolume; int16 _lastRandomSoundIndex; - uint32 _creditsLastUpdateTicks; - uint32 _creditsNextUpdateTicks; - int _lastCreditsItemIndex; - bool _creditsEndReached; - CreditsItems _creditsItems; - char *_creditsCurrText; + DuckmanCredits *_credits; // Special code interface functions void runSpecialCode(uint32 specialCodeId, OpCall &opCall); diff --git a/engines/illusions/duckman/scriptopcodes_duckman.cpp b/engines/illusions/duckman/scriptopcodes_duckman.cpp index 759b4bc606..251800268c 100644 --- a/engines/illusions/duckman/scriptopcodes_duckman.cpp +++ b/engines/illusions/duckman/scriptopcodes_duckman.cpp @@ -259,7 +259,7 @@ void ScriptOpcodes_Duckman::opUnloadResourcesBySceneId(ScriptThread *scriptThrea //static uint dsceneId = 0, dthreadId = 0; //static uint dsceneId = 0x00010008, dthreadId = 0x00020029;//Beginning in Jac -static uint dsceneId = 0x0001000A, dthreadId = 0x00020043;//Home front +//static uint dsceneId = 0x0001000A, dthreadId = 0x00020043;//Home front //static uint dsceneId = 0x0001000E, dthreadId = 0x0002007C; //static uint dsceneId = 0x00010012, dthreadId = 0x0002009D;//Paramount //static uint dsceneId = 0x00010020, dthreadId = 0x00020112;//Xmas @@ -276,7 +276,7 @@ static uint dsceneId = 0x0001000A, dthreadId = 0x00020043;//Home front //static uint dsceneId = 0x10002, dthreadId = 0x20001;//Debug menu, not supported //static uint dsceneId = 0x10044, dthreadId = 0x000202B8; // Starship Enterprise //static uint dsceneId = 0x00010039, dthreadId = 0x00020089; // Map -//static uint dsceneId = 0x00010052, dthreadId = 0x00020347; // Credits +static uint dsceneId = 0x00010052, dthreadId = 0x00020347; // Credits void ScriptOpcodes_Duckman::opChangeScene(ScriptThread *scriptThread, OpCall &opCall) { ARG_SKIP(2); diff --git a/engines/illusions/module.mk b/engines/illusions/module.mk index 82116960ca..1f164cdff9 100644 --- a/engines/illusions/module.mk +++ b/engines/illusions/module.mk @@ -16,6 +16,7 @@ MODULE_OBJS := \ cursor.o \ detection.o \ dictionary.o \ + duckman/duckman_credits.o \ duckman/duckman_dialog.o \ duckman/duckman_inventory.o \ duckman/duckman_screenshakereffects.o \ |