aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjohndoe1232012-10-27 22:18:54 +0000
committerWillem Jan Palenstijn2013-05-08 20:47:37 +0200
commit6be5c1171332764dacad9113250ede7e765bb361 (patch)
tree120fe627fe506f8644a03ad2f835c8e8210a4715
parent0022c57858f5cac3544692ad134a2446c4f3be3a (diff)
downloadscummvm-rg350-6be5c1171332764dacad9113250ede7e765bb361.tar.gz
scummvm-rg350-6be5c1171332764dacad9113250ede7e765bb361.tar.bz2
scummvm-rg350-6be5c1171332764dacad9113250ede7e765bb361.zip
NEVERHOOD: More work on the menu system:
- Add handling of ascii and system key input - Fix TextSurface::drawChar() - Pause audio when entering the menu, resume it again afterwards - Add TextEditWidget - Add SaveGameMenu (doesn't actually save anything yet and needs more work)
-rw-r--r--engines/neverhood/gamemodule.cpp32
-rw-r--r--engines/neverhood/gamemodule.h4
-rw-r--r--engines/neverhood/graphics.cpp6
-rw-r--r--engines/neverhood/menumodule.cpp522
-rw-r--r--engines/neverhood/menumodule.h92
-rw-r--r--engines/neverhood/neverhood.cpp12
-rw-r--r--engines/neverhood/scene.cpp27
-rw-r--r--engines/neverhood/scene.h2
8 files changed, 520 insertions, 177 deletions
diff --git a/engines/neverhood/gamemodule.cpp b/engines/neverhood/gamemodule.cpp
index 65164859c9..ce72a22835 100644
--- a/engines/neverhood/gamemodule.cpp
+++ b/engines/neverhood/gamemodule.cpp
@@ -123,13 +123,6 @@ void GameModule::handleMouseUp(int16 x, int16 y) {
}
}
-void GameModule::handleEscapeKey() {
- if (!_prevChildObject /* && _canRequestMainMenu TODO?*/)
- _mainMenuRequested = true;
- else
- sendMessage(_childObject, 0x000C, 0);
-}
-
void GameModule::handleSpaceKey() {
if (_childObject) {
debug(2, "GameModule::handleSpaceKey()");
@@ -137,6 +130,31 @@ void GameModule::handleSpaceKey() {
}
}
+void GameModule::handleAsciiKey(char key) {
+ if (_childObject) {
+ debug(2, "GameModule::handleAsciiKey()");
+ sendMessage(_childObject, 0x000A, (uint32)key);
+ }
+}
+
+void GameModule::handleKeyDown(Common::KeyCode keyCode) {
+ if (_childObject) {
+ if (keyCode == Common::KEYCODE_ESCAPE)
+ handleEscapeKey();
+ else if (keyCode == Common::KEYCODE_SPACE)
+ handleSpaceKey();
+ debug(2, "GameModule::handleKeyDown()");
+ sendMessage(_childObject, 0x000B, keyCode);
+ }
+}
+
+void GameModule::handleEscapeKey() {
+ if (!_prevChildObject /* && _canRequestMainMenu TODO?*/)
+ _mainMenuRequested = true;
+ else if (_childObject)
+ sendMessage(_childObject, 0x000C, 0);
+}
+
void GameModule::initKeySlotsPuzzle() {
if (!getSubVar(VA_IS_PUZZLE_INIT, 0x25400B10)) {
NonRepeatingRandomNumbers keySlots(_vm->_rnd, 16);
diff --git a/engines/neverhood/gamemodule.h b/engines/neverhood/gamemodule.h
index 8fafe2ba9e..81ebfb85bb 100644
--- a/engines/neverhood/gamemodule.h
+++ b/engines/neverhood/gamemodule.h
@@ -37,8 +37,10 @@ public:
void handleMouseMove(int16 x, int16 y);
void handleMouseDown(int16 x, int16 y);
void handleMouseUp(int16 x, int16 y);
- void handleEscapeKey();
void handleSpaceKey();
+ void handleAsciiKey(char key);
+ void handleKeyDown(Common::KeyCode keyCode);
+ void handleEscapeKey();
void initKeySlotsPuzzle();
void initMemoryPuzzle();
void initWaterPipesPuzzle();
diff --git a/engines/neverhood/graphics.cpp b/engines/neverhood/graphics.cpp
index b87c447b31..81cec9f46d 100644
--- a/engines/neverhood/graphics.cpp
+++ b/engines/neverhood/graphics.cpp
@@ -180,7 +180,7 @@ TextSurface::TextSurface(NeverhoodEngine *vm, uint32 fileHash, uint16 numRows, u
: BaseSurface(vm, 0, charWidth * charCount, charHeight * numRows),
_numRows(numRows), _firstChar(firstChar), _charWidth(charWidth), _charHeight(charHeight),
_fileHash(fileHash), _charCount(charCount) {
-
+
SpriteResource spriteResource(_vm);
spriteResource.load2(_fileHash);
drawSpriteResourceEx(spriteResource, false, false, 0, 0);
@@ -189,8 +189,8 @@ TextSurface::TextSurface(NeverhoodEngine *vm, uint32 fileHash, uint16 numRows, u
void TextSurface::drawChar(BaseSurface *destSurface, int16 x, int16 y, byte chr) {
NDrawRect sourceRect;
chr -= _firstChar;
- sourceRect.x = (chr % 16) * _charWidth;
- sourceRect.y = (chr / 16) * _charHeight;
+ sourceRect.x = (chr % _charCount) * _charWidth;
+ sourceRect.y = (chr / _charCount) * _charHeight;
sourceRect.width = _charWidth;
sourceRect.height = _charHeight;
destSurface->copyFrom(_surface, x, y, sourceRect, true);
diff --git a/engines/neverhood/menumodule.cpp b/engines/neverhood/menumodule.cpp
index 7e1198abd0..6a82c47e8e 100644
--- a/engines/neverhood/menumodule.cpp
+++ b/engines/neverhood/menumodule.cpp
@@ -27,7 +27,8 @@ namespace Neverhood {
enum {
MAIN_MENU = 0,
CREDITS_SCENE = 1,
- MAKING_OF = 2
+ MAKING_OF = 2,
+ SAVE_GAME_MENU = 3
};
static const uint32 kMakingOfSmackerFileHashList[] = {
@@ -48,22 +49,18 @@ static const uint32 kMakingOfSmackerFileHashList[] = {
};
MenuModule::MenuModule(NeverhoodEngine *vm, Module *parentModule, int which)
- : Module(vm, parentModule) {
+ : Module(vm, parentModule), _savegameList(NULL) {
SetMessageHandler(&MenuModule::handleMessage);
- // TODO Check if the background actually needs to be saved
- _savedBackground = new Background(_vm, 0);
- _savedBackground->createSurface(0, 640, 480);
- // TODO Save current palette
- // TODO Stop all sounds and music
-
_savedPaletteData = _vm->_screen->getPaletteData();
+ _vm->_mixer->pauseAll(true);
createScene(MAIN_MENU, -1);
}
MenuModule::~MenuModule() {
+ _vm->_mixer->pauseAll(false);
_vm->_screen->setPaletteData(_savedPaletteData);
}
@@ -79,6 +76,9 @@ void MenuModule::createScene(int sceneNum, int which) {
case MAKING_OF:
createSmackerScene(kMakingOfSmackerFileHashList, false, true, true);
break;
+ case SAVE_GAME_MENU:
+ createSaveGameMenu();
+ break;
}
SetUpdateHandler(&MenuModule::updateScene);
_childObject->handleUpdate();
@@ -100,7 +100,7 @@ void MenuModule::updateScene() {
break;
case 2:
debug("SAVE GAME");
- // TODO createSaveGameMenu();
+ createScene(SAVE_GAME_MENU, -1);
break;
case 3:
debug("RESUME GAME");
@@ -137,6 +137,9 @@ void MenuModule::updateScene() {
case MAKING_OF:
createScene(MAIN_MENU, -1);
break;
+ case SAVE_GAME_MENU:
+ handleSaveGameMenuAction(_moduleResult);
+ break;
default:
break;
}
@@ -148,60 +151,38 @@ uint32 MenuModule::handleMessage(int messageNum, const MessageParam &param, Enti
return Module::handleMessage(messageNum, param, sender);;
}
-static const uint32 kMainMenuButtonFileHashes[] = {
- 0x36C62120,
- 0x56C62120,
- 0x96C62120,
- 0x16C62121,
- 0x16C62122,
- 0x16C62124,
- 0x16C62128,
- 0x16C62130,
- 0x16C62100
-};
+void MenuModule::createSaveGameMenu() {
+ // TODO Load actual savegames list :)
+ _savegameList = new StringArray();
+ _savegameList->push_back(Common::String("Annoying scene"));
+ _savegameList->push_back(Common::String("Stuff happens"));
+ for (uint i = 0; i < 33; ++i)
+ _savegameList->push_back(Common::String::format("Game %d", i));
+ _childObject = new SaveGameMenu(_vm, this, _savegameList);
+}
-MainMenuButton::MainMenuButton(NeverhoodEngine *vm, Scene *parentScene, uint buttonIndex)
- : StaticSprite(vm, 900), _parentScene(parentScene), _buttonIndex(buttonIndex), _countdown(0) {
+void MenuModule::handleSaveGameMenuAction(int action) {
+ if (action != 0) {
+ createScene(MAIN_MENU, -1);
+ } else {
+ // TODO Actual saving later 0048A62E
+ createScene(MAIN_MENU, -1);
+ }
+ delete _savegameList;
+ _savegameList = NULL;
+}
- loadSprite(kMainMenuButtonFileHashes[_buttonIndex], kSLFDefDrawOffset | kSLFDefPosition, 100);
+MenuButton::MenuButton(NeverhoodEngine *vm, Scene *parentScene, uint buttonIndex, uint32 fileHash, const NRect &collisionBounds)
+ : StaticSprite(vm, 900), _parentScene(parentScene), _buttonIndex(buttonIndex), _countdown(0) {
- // TODO Move to const array
- switch (_buttonIndex) {
- case 0:
- _collisionBounds.set(52, 121, 110, 156);
- break;
- case 1:
- _collisionBounds.set(52, 192, 109, 222);
- break;
- case 2:
- _collisionBounds.set(60, 257, 119, 286);
- break;
- case 3:
- _collisionBounds.set(67, 326, 120, 354);
- break;
- case 4:
- _collisionBounds.set(70, 389, 128, 416);
- break;
- case 5:
- _collisionBounds.set(523, 113, 580, 144);
- break;
- case 6:
- _collisionBounds.set(525, 176, 577, 206);
- break;
- case 7:
- _collisionBounds.set(527, 384, 580, 412);
- break;
- case 8:
- _collisionBounds.set(522, 255, 580, 289);
- break;
- }
-
+ loadSprite(fileHash, kSLFDefDrawOffset | kSLFDefPosition, 100);
+ _collisionBounds = collisionBounds;
setVisible(false);
- SetUpdateHandler(&MainMenuButton::update);
- SetMessageHandler(&MainMenuButton::handleMessage);
+ SetUpdateHandler(&MenuButton::update);
+ SetMessageHandler(&MenuButton::handleMessage);
}
-void MainMenuButton::update() {
+void MenuButton::update() {
updatePosition();
if (_countdown != 0 && (--_countdown) == 0) {
setVisible(false);
@@ -209,7 +190,7 @@ void MainMenuButton::update() {
}
}
-uint32 MainMenuButton::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
+uint32 MenuButton::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
uint32 messageResult = Sprite::handleMessage(messageNum, param, sender);
switch (messageNum) {
case 0x1011:
@@ -226,6 +207,30 @@ uint32 MainMenuButton::handleMessage(int messageNum, const MessageParam &param,
MainMenu::MainMenu(NeverhoodEngine *vm, Module *parentModule)
: Scene(vm, parentModule, true) {
+ static const uint32 kMenuButtonFileHashes[] = {
+ 0x36C62120,
+ 0x56C62120,
+ 0x96C62120,
+ 0x16C62121,
+ 0x16C62122,
+ 0x16C62124,
+ 0x16C62128,
+ 0x16C62130,
+ 0x16C62100
+ };
+
+ static const NRect kMenuButtonCollisionBounds[] = {
+ NRect(52, 121, 110, 156),
+ NRect(52, 192, 109, 222),
+ NRect(60, 257, 119, 286),
+ NRect(67, 326, 120, 354),
+ NRect(70, 389, 128, 416),
+ NRect(523, 113, 580, 144),
+ NRect(525, 176, 577, 206),
+ NRect(527, 384, 580, 412),
+ NRect(522, 255, 580, 289)
+ };
+
setBackground(0x08C0020C);
setPalette(0x08C0020C);
insertMouse433(0x00208084);
@@ -233,12 +238,13 @@ MainMenu::MainMenu(NeverhoodEngine *vm, Module *parentModule)
insertStaticSprite(0x41137051, 100);
insertStaticSprite(0xC10B2015, 100);
- // TODO Only is music is disabled
+ // TODO Only if music is enabled
_musicOnButton = insertStaticSprite(0x0C24C0EE, 100);
for (uint buttonIndex = 0; buttonIndex < 9; ++buttonIndex) {
- Sprite *mainMenuButton = insertSprite<MainMenuButton>(this, buttonIndex);
- _vm->_collisionMan->addSprite(mainMenuButton);
+ Sprite *menuButton = insertSprite<MenuButton>(this, buttonIndex,
+ kMenuButtonFileHashes[buttonIndex], kMenuButtonCollisionBounds[buttonIndex]);
+ _vm->_collisionMan->addSprite(menuButton);
}
SetUpdateHandler(&Scene::update);
@@ -341,7 +347,7 @@ uint32 CreditsScene::handleMessage(int messageNum, const MessageParam &param, En
leaveScene(0);
break;
case 0x000B://TODO Implement this message
- if (param.asInteger() == 27 && _canAbort)
+ if (param.asInteger() == Common::KEYCODE_ESCAPE && _canAbort)
leaveScene(0);
break;
case 0x101D:
@@ -358,9 +364,11 @@ WidgetScene::WidgetScene(NeverhoodEngine *vm, Module *parentModule)
: Scene(vm, parentModule, true), _currWidget(NULL) {
}
-void WidgetScene::getMousePos(NPoint &pt) {
+NPoint WidgetScene::getMousePos() {
+ NPoint pt;
pt.x = _mouseCursor->getX();
pt.y = _mouseCursor->getY();
+ return pt;
}
void WidgetScene::setCurrWidget(Widget *newWidget) {
@@ -372,10 +380,13 @@ void WidgetScene::setCurrWidget(Widget *newWidget) {
}
}
+void WidgetScene::handleEvent(int16 itemID, int eventType) {
+}
+
Widget::Widget(NeverhoodEngine *vm, int16 x, int16 y, int16 itemID, WidgetScene *parentScene,
- int baseObjectPriority, int baseSurfacePriority, bool visible)
+ int baseObjectPriority, int baseSurfacePriority)
: StaticSprite(vm, baseObjectPriority), _itemID(itemID), _parentScene(parentScene),
- _baseObjectPriority(baseObjectPriority), _baseSurfacePriority(baseSurfacePriority), _visible(visible) {
+ _baseObjectPriority(baseObjectPriority), _baseSurfacePriority(baseSurfacePriority) {
SetUpdateHandler(&Widget::update);
SetMessageHandler(&Widget::handleMessage);
@@ -383,18 +394,6 @@ Widget::Widget(NeverhoodEngine *vm, int16 x, int16 y, int16 itemID, WidgetScene
setPosition(x, y);
}
-void Widget::show() {
- if (_surface)
- _surface->setVisible(true);
- _visible = true;
-}
-
-void Widget::hide() {
- if (_surface)
- _surface->setVisible(false);
- _visible = false;
-}
-
void Widget::onClick() {
_parentScene->setCurrWidget(this);
// TODO _parentScene->onClick(_itemID, 0);
@@ -451,9 +450,9 @@ uint32 Widget::handleMessage(int messageNum, const MessageParam &param, Entity *
}
TextLabelWidget::TextLabelWidget(NeverhoodEngine *vm, int16 x, int16 y, int16 itemID, WidgetScene *parentScene,
- int baseObjectPriority, int baseSurfacePriority, bool visible,
+ int baseObjectPriority, int baseSurfacePriority,
const byte *string, int stringLen, BaseSurface *drawSurface, int16 tx, int16 ty, TextSurface *textSurface)
- : Widget(vm, x, y, itemID, parentScene, baseObjectPriority, baseSurfacePriority, visible),
+ : Widget(vm, x, y, itemID, parentScene, baseObjectPriority, baseSurfacePriority),
_string(string), _stringLen(stringLen), _drawSurface(drawSurface), _tx(tx), _ty(ty), _textSurface(textSurface) {
}
@@ -473,13 +472,11 @@ int16 TextLabelWidget::getHeight() {
void TextLabelWidget::drawString(int maxStringLength) {
_textSurface->drawString(_drawSurface, _x, _y, _string, MIN(_stringLen, maxStringLength));
- _visible = true;
_collisionBoundsOffset.set(_tx, _ty, getWidth(), getHeight());
updateBounds();
}
void TextLabelWidget::clear() {
- _visible = false;
_collisionBoundsOffset.set(0, 0, 0, 0);
updateBounds();
}
@@ -498,47 +495,215 @@ void TextLabelWidget::setTY(int16 ty) {
_ty = ty;
}
+TextEditWidget::TextEditWidget(NeverhoodEngine *vm, int16 x, int16 y, int16 itemID, WidgetScene *parentScene,
+ int baseObjectPriority, int baseSurfacePriority,
+ const byte *string, int maxStringLength, TextSurface *textSurface, uint32 fileHash, const NRect &rect)
+ : Widget(vm, x, y, itemID, parentScene, baseObjectPriority, baseSurfacePriority),
+ _maxStringLength(maxStringLength), _textSurface(textSurface), _fileHash(fileHash), _rect(rect),
+ _cursorSurface(NULL), _cursorTicks(0), _cursorPos(0), _cursorFileHash(0), _cursorWidth(0), _cursorHeight(0) {
+
+ _entryString = (const char*)string;
+ _maxVisibleChars = (_rect.x2 - _rect.x1) / _textSurface->getCharWidth();
+ _cursorPos = _entryString.size();
+
+ SetUpdateHandler(&TextEditWidget::update);
+ SetMessageHandler(&TextEditWidget::handleMessage);
+}
+
+TextEditWidget::~TextEditWidget() {
+ delete _cursorSurface;
+}
+
+void TextEditWidget::onClick() {
+ NPoint mousePos = _parentScene->getMousePos();
+ mousePos.x -= _x + _rect.x1;
+ mousePos.y -= _y + _rect.y1;
+ if (mousePos.x >= 0 && mousePos.x <= _rect.x2 - _rect.x1 &&
+ mousePos.y >= 0 && mousePos.y <= _rect.y2 - _rect.y1) {
+ if (_entryString.size() == 1)
+ _cursorPos = 0;
+ else {
+ int newCursorPos = mousePos.x / _textSurface->getCharWidth();
+ if (mousePos.x % _textSurface->getCharWidth() > _textSurface->getCharWidth() / 2 && newCursorPos <= (int)_entryString.size())//###
+ ++newCursorPos;
+ _cursorPos = MIN((int)_entryString.size(), newCursorPos);
+ }
+ _cursorSurface->setVisible(true);
+ refresh();
+ }
+ Widget::onClick();
+}
+
+void TextEditWidget::addSprite() {
+ SpriteResource cursorSpriteResource(_vm);
+
+ _spriteResource.load2(_fileHash);
+ createSurface(_baseSurfacePriority, _spriteResource.getDimensions().width, _spriteResource.getDimensions().height);
+ refreshPosition();
+ _parentScene->addSprite(this);
+ _vm->_collisionMan->addSprite(this);
+ _surface->setVisible(true);
+ _textLabelWidget = new TextLabelWidget(_vm, _rect.x1, _rect.y1 + (_rect.y2 - _rect.y1 + 1 - _textSurface->getCharHeight()) / 2,
+ 0, _parentScene, _baseObjectPriority + 1, _baseSurfacePriority + 1,
+ (const byte*)_entryString.c_str(), _entryString.size(), _surface, _x, _y, _textSurface);
+ _textLabelWidget->addSprite();
+ cursorSpriteResource.load2(_cursorFileHash);
+ _cursorSurface = new BaseSurface(_vm, 0, cursorSpriteResource.getDimensions().width, cursorSpriteResource.getDimensions().height);
+ _cursorSurface->drawSpriteResourceEx(cursorSpriteResource, false, false, cursorSpriteResource.getDimensions().width, cursorSpriteResource.getDimensions().height);
+ _cursorSurface->setVisible(true);
+ refresh();
+}
+
+void TextEditWidget::enterWidget() {
+ _cursorSurface->setVisible(true);
+ refresh();
+}
+
+void TextEditWidget::exitWidget() {
+ _cursorSurface->setVisible(false);
+ refresh();
+}
+
+void TextEditWidget::setCursor(uint32 cursorFileHash, int16 cursorWidth, int16 cursorHeight) {
+ _cursorFileHash = cursorFileHash;
+ _cursorWidth = cursorWidth;
+ _cursorHeight = cursorHeight;
+}
+
+void TextEditWidget::drawCursor() {
+ if (_cursorSurface->getVisible() && _cursorPos >= 0 && _cursorPos <= _maxVisibleChars) {
+ NDrawRect sourceRect(0, 0, _cursorWidth, _cursorHeight);
+ _surface->copyFrom(_cursorSurface->getSurface(), _rect.x1 + _cursorPos * _textSurface->getCharWidth(),
+ _rect.y1 + (_rect.y2 - _cursorHeight - _rect.y1 + 1) / 2, sourceRect, true);
+ } else
+ _cursorSurface->setVisible(false);
+}
+
+void TextEditWidget::updateString() {
+ _textLabelWidget->setString((const byte *)_entryString.c_str(), _entryString.size());
+ _textLabelWidget->drawString(_maxVisibleChars);
+}
+
+void TextEditWidget::getString(Common::String &string) {
+ string = _entryString;
+}
+
+void TextEditWidget::setString(const Common::String &string) {
+ _entryString = string;
+ _cursorPos = _entryString.size();
+ refresh();
+}
+
+void TextEditWidget::handleAsciiKey(char ch) {
+ if ((int)_entryString.size() < _maxStringLength &&
+ ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch >= '0' && ch <= '9') || ch == ' ')) {
+ _entryString.insertChar(ch, _cursorPos);
+ ++_cursorPos;
+ refresh();
+ }
+}
+
+void TextEditWidget::handleKeyDown(Common::KeyCode keyCode) {
+ bool doRefresh = true;
+ switch (keyCode) {
+ case Common::KEYCODE_DELETE:
+ if (_entryString.size() > 0 && _cursorPos < (int)_entryString.size())
+ _entryString.deleteChar(_cursorPos);
+ break;
+ case Common::KEYCODE_HOME:
+ _cursorPos = 0;
+ break;
+ case Common::KEYCODE_END:
+ _cursorPos = _entryString.size();
+ break;
+ case Common::KEYCODE_LEFT:
+ if (_entryString.size() > 0 && _cursorPos > 0)
+ --_cursorPos;
+ break;
+ case Common::KEYCODE_RIGHT:
+ if (_cursorPos < (int)_entryString.size())
+ ++_cursorPos;
+ break;
+ case Common::KEYCODE_BACKSPACE:
+ if (_entryString.size() > 0 && _cursorPos > 0)
+ _entryString.deleteChar(--_cursorPos);
+ break;
+ default:
+ break;
+ }
+ if (doRefresh) {
+ _cursorSurface->setVisible(true);
+ _cursorTicks = 0;
+ refresh();
+ }
+}
+
+void TextEditWidget::refresh() {
+ refreshPosition();
+ updateString();
+ drawCursor();
+}
+
+void TextEditWidget::update() {
+ Widget::update();
+ if (_parentScene->getCurrWidget() == this && _cursorTicks++ == 10) {
+ _cursorSurface->setVisible(!_cursorSurface->getVisible());
+ refresh();
+ _cursorTicks = 0;
+ }
+}
+
+uint32 TextEditWidget::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = Widget::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x000A:
+ handleAsciiKey(param.asInteger());
+ break;
+ case 0x000B:
+ handleKeyDown((Common::KeyCode)param.asInteger());
+ break;
+ }
+ return messageResult;
+}
+
SavegameListBox::SavegameListBox(NeverhoodEngine *vm, int16 x, int16 y, int16 itemID, WidgetScene *parentScene,
- int baseObjectPriority, int baseSurfacePriority, bool visible,
- StringArray *savegameList, TextSurface *textSurface1, TextSurface *textSurface2, uint32 fileHash1, NRect &rect)
- : Widget(vm, x, y, itemID, parentScene, baseObjectPriority, baseSurfacePriority, visible),
- _savegameList(savegameList), _textSurface1(textSurface1), _textSurface2(textSurface2), _fileHash1(fileHash1), _rect(rect),
- _maxStringLength(0), _topIndex(0), _visibleItemsCount(0), _currIndex(0) {
+ int baseObjectPriority, int baseSurfacePriority,
+ StringArray *savegameList, TextSurface *textSurface, uint32 bgFileHash, const NRect &rect)
+ : Widget(vm, x, y, itemID, parentScene, baseObjectPriority, baseSurfacePriority),
+ _savegameList(savegameList), _textSurface(textSurface), _bgFileHash(bgFileHash), _rect(rect),
+ _maxStringLength(0), _firstVisibleItem(0), _lastVisibleItem(0), _currIndex(0) {
- _maxVisibleItemsCount = (_rect.y2 - _rect.y1) / _textSurface1->getCharHeight();
- _maxStringLength = (_rect.x2 - _rect.x1) / _textSurface1->getCharWidth();
+ _maxVisibleItemsCount = (_rect.y2 - _rect.y1) / _textSurface->getCharHeight();
+ _maxStringLength = (_rect.x2 - _rect.x1) / _textSurface->getCharWidth();
}
void SavegameListBox::onClick() {
- NPoint mousePos;
- int16 w = _rect.x2 - _rect.x1, h = _rect.y2 - _rect.y1;
- _parentScene->getMousePos(mousePos);
+ NPoint mousePos = _parentScene->getMousePos();
mousePos.x -= _x + _rect.x1;
mousePos.y -= _y + _rect.y1;
- if (mousePos.x >= 0 && mousePos.x <= w && mousePos.y >= 0 && mousePos.y <= h) {
- int newIndex = _topIndex + mousePos.y / _textSurface1->getCharHeight();
- if (newIndex <= _visibleItemsCount) {
+ if (mousePos.x >= 0 && mousePos.x <= _rect.x2 - _rect.x1 &&
+ mousePos.y >= 0 && mousePos.y <= _rect.y2 - _rect.y1) {
+ int newIndex = _firstVisibleItem + mousePos.y / _textSurface->getCharHeight();
+ if (newIndex <= _lastVisibleItem) {
_currIndex = newIndex;
refresh();
_parentScene->setCurrWidget(this);
- // TODO _parentScene->onClick(_itemID, 5);
+ debug("_currIndex = %d", _currIndex);
+ _parentScene->handleEvent(_itemID, 5);
}
}
}
void SavegameListBox::addSprite() {
- _spriteResource.load2(_fileHash1);
+ _spriteResource.load2(_bgFileHash);
createSurface(_baseSurfacePriority, _spriteResource.getDimensions().width, _spriteResource.getDimensions().height);
refreshPosition();
_parentScene->addSprite(this);
_vm->_collisionMan->addSprite(this);
- if (_visible)
- show();
- else
- hide();
+ _surface->setVisible(true);
buildItems();
- _topIndex = 0;
- _visibleItemsCount = MIN(_maxVisibleItemsCount, (int)_textLabelItems.size());
+ _firstVisibleItem = 0;
+ _lastVisibleItem = MIN(_maxVisibleItemsCount, (int)_textLabelItems.size());
refresh();
}
@@ -549,7 +714,7 @@ void SavegameListBox::buildItems() {
const byte *string = (const byte*)savegameList[i].c_str();
int stringLen = (int)savegameList[i].size();
TextLabelWidget *label = new TextLabelWidget(_vm, itemX, itemY, i, _parentScene, _baseObjectPriority + 1,
- _baseSurfacePriority + 1, _visible, string, MIN(stringLen, _maxStringLength), _surface, _x, _y, _textSurface1);
+ _baseSurfacePriority + 1, string, MIN(stringLen, _maxStringLength), _surface, _x, _y, _textSurface);
label->addSprite();
_textLabelItems.push_back(label);
}
@@ -558,13 +723,12 @@ void SavegameListBox::buildItems() {
void SavegameListBox::drawItems() {
for (int i = 0; i < (int)_textLabelItems.size(); ++i) {
TextLabelWidget *label = _textLabelItems[i];
- if (i >= _topIndex && i <= _visibleItemsCount) {
- label->setY(_rect.y1 + (i - _topIndex) * _textSurface1->getCharHeight());
+ if (i >= _firstVisibleItem && i < _lastVisibleItem) {
+ label->setY(_rect.y1 + (i - _firstVisibleItem) * _textSurface->getCharHeight());
label->updateBounds();
label->drawString(_maxStringLength);
- } else {
+ } else
label->clear();
- }
}
}
@@ -574,37 +738,153 @@ void SavegameListBox::refresh() {
}
void SavegameListBox::scrollUp() {
- if (_topIndex > 0) {
- --_topIndex;
- --_visibleItemsCount;
+ if (_firstVisibleItem > 0) {
+ --_firstVisibleItem;
+ --_lastVisibleItem;
refresh();
}
}
void SavegameListBox::scrollDown() {
- if (_visibleItemsCount < (int)_textLabelItems.size()) {
- ++_topIndex;
- ++_visibleItemsCount;
+ if (_lastVisibleItem < (int)_textLabelItems.size()) {
+ ++_firstVisibleItem;
+ ++_lastVisibleItem;
refresh();
}
}
void SavegameListBox::pageUp() {
- int distance = MIN(_topIndex, _maxVisibleItemsCount);
- if (distance > 0) {
- _topIndex -= distance;
- _visibleItemsCount = distance;
+ int amount = MIN(_firstVisibleItem, _maxVisibleItemsCount);
+ if (amount > 0) {
+ _firstVisibleItem -= amount;
+ _lastVisibleItem -= amount;
refresh();
}
}
void SavegameListBox::pageDown() {
- int distance = MIN((int)_textLabelItems.size() - _visibleItemsCount - 1, _maxVisibleItemsCount);
- if (distance > 0) {
- _topIndex += distance;
- _visibleItemsCount += distance;
+ int amount = MIN((int)_textLabelItems.size() - _lastVisibleItem, _maxVisibleItemsCount);
+ if (amount > 0) {
+ _firstVisibleItem += amount;
+ _lastVisibleItem += amount;
refresh();
}
}
+SaveGameMenu::SaveGameMenu(NeverhoodEngine *vm, Module *parentModule, StringArray *savegameList)
+ : WidgetScene(vm, parentModule), _savegameList(savegameList) {
+
+ static const uint32 kSaveGameMenuButtonFileHashes[] = {
+ 0x8359A824,
+ 0x0690E260,
+ 0x0352B050,
+ 0x1392A223,
+ 0x13802260,
+ 0x0B32B200
+ };
+
+ static const NRect kSaveGameMenuButtonCollisionBounds[] = {
+ NRect(518, 106, 602, 160),
+ NRect(516, 378, 596, 434),
+ NRect(394, 108, 458, 206),
+ NRect(400, 204, 458, 276),
+ NRect(398, 292, 456, 352),
+ NRect(396, 352, 460, 444)
+ };
+
+ static const NRect kListBoxRect(0, 0, 320, 272);
+ static const NRect kTextEditRect(0, 0, 377, 17);
+ static const NRect kMouseRect(50, 47, 427, 64);
+
+ _textSurface = new TextSurface(_vm, 0x2328121A, 7, 32, 32, 11, 17);
+
+ setBackground(0x30084E25);
+ setPalette(0x30084E25);
+ insertMouse433(0x84E21308, &kMouseRect);
+ insertStaticSprite(0x1340A5C2, 200);
+ insertStaticSprite(0x1301A7EA, 200);
+
+ _listBox = new SavegameListBox(_vm, 60, 142, 69/*ItemID*/, this, 1000, 1000,
+ _savegameList, _textSurface, 0x1115A223, kListBoxRect);
+ _listBox->addSprite();
+
+ _textEditWidget = new TextEditWidget(_vm, 50, 47, 70/*ItemID*/, this, 1000, 1000,
+ (const byte*)_savegameName.c_str(), 29, _textSurface, 0x3510A868, kTextEditRect);
+ _textEditWidget->setCursor(0x8290AC20, 2, 13);
+ _textEditWidget->addSprite();
+ _textEditWidget->setString(_savegameName);
+ setCurrWidget(_textEditWidget);
+
+ for (uint buttonIndex = 0; buttonIndex < 6; ++buttonIndex) {
+ Sprite *menuButton = insertSprite<MenuButton>(this, buttonIndex,
+ kSaveGameMenuButtonFileHashes[buttonIndex], kSaveGameMenuButtonCollisionBounds[buttonIndex]);
+ _vm->_collisionMan->addSprite(menuButton);
+ }
+
+
+ SetUpdateHandler(&Scene::update);
+ SetMessageHandler(&SaveGameMenu::handleMessage);
+}
+
+SaveGameMenu::~SaveGameMenu() {
+ delete _textSurface;
+}
+
+void SaveGameMenu::handleEvent(int16 itemID, int eventType) {
+ if (itemID == 69 && eventType == 5) {
+ uint currIndex = _listBox->getCurrIndex();
+ _textEditWidget->setString((*_savegameList)[currIndex]);
+ setCurrWidget(_textEditWidget);
+ }
+}
+
+uint32 SaveGameMenu::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
+ Scene::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x000A:
+ sendMessage(_textEditWidget, 0x000A, param.asInteger());
+ setCurrWidget(_textEditWidget);
+ break;
+ case 0x000B:
+ if (param.asInteger() == Common::KEYCODE_RETURN) {
+ // Return
+ // TODO 00486B05
+ // Get string from edit field and inform main module
+ leaveScene(0);
+ } else if (param.asInteger() == Common::KEYCODE_ESCAPE) {
+ // Escape
+ leaveScene(1);
+ } else {
+ sendMessage(_textEditWidget, 0x000B, param.asInteger());
+ setCurrWidget(_textEditWidget);
+ }
+ break;
+ case 0x2000:
+ // Handle menu button click
+ switch (param.asInteger()) {
+ case 0:
+ // TODO Same handling as Return
+ leaveScene(0);
+ break;
+ case 1:
+ leaveScene(1);
+ break;
+ case 2:
+ _listBox->pageUp();
+ break;
+ case 3:
+ _listBox->scrollUp();
+ break;
+ case 4:
+ _listBox->scrollDown();
+ break;
+ case 5:
+ _listBox->pageDown();
+ break;
+ }
+ break;
+ }
+ return 0;
+}
+
} // End of namespace Neverhood
diff --git a/engines/neverhood/menumodule.h b/engines/neverhood/menumodule.h
index 1d7678d4bf..7c1e6e1041 100644
--- a/engines/neverhood/menumodule.h
+++ b/engines/neverhood/menumodule.h
@@ -30,6 +30,8 @@
namespace Neverhood {
+typedef Common::Array<Common::String> StringArray;
+
class MenuModule : public Module {
public:
MenuModule(NeverhoodEngine *vm, Module *parentModule, int which);
@@ -37,17 +39,18 @@ public:
protected:
int _sceneNum;
Common::String _savegameName;
- Background *_savedBackground;
byte *_savedPaletteData;
- // TODO _savegameList (list of strings?)
+ StringArray *_savegameList;
void createScene(int sceneNum, int which);
void updateScene();
uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+ void createSaveGameMenu();
+ void handleSaveGameMenuAction(int action);
};
-class MainMenuButton : public StaticSprite {
+class MenuButton : public StaticSprite {
public:
- MainMenuButton(NeverhoodEngine *vm, Scene *parentScene, uint buttonIndex);
+ MenuButton(NeverhoodEngine *vm, Scene *parentScene, uint buttonIndex, uint32 fileHash, const NRect &collisionBounds);
protected:
Scene *_parentScene;
int _countdown;
@@ -79,15 +82,15 @@ protected:
uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
};
-typedef Common::Array<Common::String> StringArray;
-
class Widget;
class WidgetScene : public Scene {
public:
WidgetScene(NeverhoodEngine *vm, Module *parentModule);
- void getMousePos(NPoint &pt);
+ NPoint getMousePos();
virtual void setCurrWidget(Widget *newWidget);
+ virtual Widget *getCurrWidget() { return _currWidget; }
+ virtual void handleEvent(int16 itemID, int eventType);
protected:
Widget *_currWidget;
};
@@ -95,9 +98,7 @@ protected:
class Widget : public StaticSprite {
public:
Widget(NeverhoodEngine *vm, int16 x, int16 y, int16 itemID, WidgetScene *parentScene,
- int baseObjectPriority, int baseSurfacePriority, bool visible);
- virtual void show();
- virtual void hide();
+ int baseObjectPriority, int baseSurfacePriority);
virtual void onClick();
virtual void setPosition(int16 x, int16 y);
virtual void refreshPosition();
@@ -111,7 +112,6 @@ protected:
WidgetScene *_parentScene;
int _baseObjectPriority;
int _baseSurfacePriority;
- bool _visible;
void update();
uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
};
@@ -119,7 +119,7 @@ protected:
class TextLabelWidget : public Widget {
public:
TextLabelWidget(NeverhoodEngine *vm, int16 x, int16 y, int16 itemID, WidgetScene *parentScene,
- int baseObjectPriority, int baseSurfacePriority, bool visible,
+ int baseObjectPriority, int baseSurfacePriority,
const byte *string, int stringLen, BaseSurface *drawSurface, int16 tx, int16 ty, TextSurface *textSurface);
virtual void onClick();
virtual void addSprite();
@@ -138,11 +138,46 @@ protected:
int _stringLen;
};
+class TextEditWidget : public Widget {
+public:
+ TextEditWidget(NeverhoodEngine *vm, int16 x, int16 y, int16 itemID, WidgetScene *parentScene,
+ int baseObjectPriority, int baseSurfacePriority,
+ const byte *string, int maxStringLength, TextSurface *textSurface, uint32 fileHash, const NRect &rect);
+ ~TextEditWidget();
+ virtual void onClick();
+ virtual void addSprite();
+ virtual void enterWidget();
+ virtual void exitWidget();
+ void setCursor(uint32 cursorFileHash, int16 cursorWidth, int16 cursorHeight);
+ void drawCursor();
+ void updateString();
+ void getString(Common::String &string);
+ void setString(const Common::String &string);
+ void handleAsciiKey(char ch);
+ void handleKeyDown(Common::KeyCode keyCode);
+ void refresh();
+protected:
+ NRect _rect;
+ uint32 _fileHash;
+ int _maxVisibleChars;
+ int _maxStringLength;
+ int _cursorPos;
+ int _cursorTicks;
+ Common::String _entryString;
+ TextSurface *_textSurface;
+ TextLabelWidget *_textLabelWidget;
+ BaseSurface *_cursorSurface;
+ uint32 _cursorFileHash;
+ int16 _cursorWidth, _cursorHeight;
+ void update();
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+};
+
class SavegameListBox : public Widget {
public:
SavegameListBox(NeverhoodEngine *vm, int16 x, int16 y, int16 itemID, WidgetScene *parentScene,
- int baseObjectPriority, int baseSurfacePriority, bool visible,
- StringArray *savegameList, TextSurface *textSurface1, TextSurface *textSurface2, uint32 fileHash1, NRect &rect);
+ int baseObjectPriority, int baseSurfacePriority,
+ StringArray *savegameList, TextSurface *textSurface, uint32 bgFileHash, const NRect &rect);
virtual void onClick();
virtual void addSprite();
void buildItems();
@@ -152,20 +187,35 @@ public:
void scrollDown();
void pageUp();
void pageDown();
+ uint getCurrIndex() const { return _currIndex; }
protected:
- NRect _rect;
- uint32 _fileHash1;
+ const NRect _rect;
+ uint32 _bgFileHash;
int _maxStringLength;
Common::Array<TextLabelWidget*> _textLabelItems;
- int _topIndex;
- int _visibleItemsCount;
+ int _firstVisibleItem;
+ int _lastVisibleItem;
StringArray *_savegameList;
- TextSurface *_textSurface1;
- TextSurface *_textSurface2;
- int _currIndex;
+ TextSurface *_textSurface;
+ uint _currIndex;
int _maxVisibleItemsCount;
};
+class SaveGameMenu : public WidgetScene {
+public:
+ SaveGameMenu(NeverhoodEngine *vm, Module *parentModule, StringArray *savegameList);
+ ~SaveGameMenu();
+ virtual void handleEvent(int16 itemID, int eventType);
+protected:
+ StringArray *_savegameList;
+ TextSurface *_textSurface;
+ SavegameListBox *_listBox;
+ TextEditWidget *_textEditWidget;
+ Common::String _savegameName;
+ void update();
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+};
+
} // End of namespace Neverhood
#endif /* NEVERHOOD_MENUMODULE_H */
diff --git a/engines/neverhood/neverhood.cpp b/engines/neverhood/neverhood.cpp
index 9141de078a..208a1572e2 100644
--- a/engines/neverhood/neverhood.cpp
+++ b/engines/neverhood/neverhood.cpp
@@ -112,16 +112,8 @@ Common::Error NeverhoodEngine::run() {
switch (event.type) {
case Common::EVENT_KEYDOWN:
_keyState = event.kbd.keycode;
- switch (_keyState) {
- case Common::KEYCODE_ESCAPE:
- _gameModule->handleEscapeKey();
- break;
- case Common::KEYCODE_SPACE:
- _gameModule->handleSpaceKey();
- break;
- default:
- break;
- }
+ _gameModule->handleKeyDown(event.kbd.keycode);
+ _gameModule->handleAsciiKey(event.kbd.ascii);
break;
case Common::EVENT_KEYUP:
_keyState = Common::KEYCODE_INVALID;
diff --git a/engines/neverhood/scene.cpp b/engines/neverhood/scene.cpp
index 9e49c6b137..aa4efaca13 100644
--- a/engines/neverhood/scene.cpp
+++ b/engines/neverhood/scene.cpp
@@ -100,28 +100,29 @@ void Scene::addEntity(Entity *entity) {
}
bool Scene::removeEntity(Entity *entity) {
- for (uint index = 0; index < _entities.size(); index++) {
+ for (uint index = 0; index < _entities.size(); index++)
if (_entities[index] == entity) {
_entities.remove_at(index);
return true;
}
- }
return false;
}
void Scene::addSurface(BaseSurface *surface) {
- int index = 0, insertIndex = -1;
- for (Common::Array<BaseSurface*>::iterator iter = _surfaces.begin(); iter != _surfaces.end(); iter++) {
- if ((*iter)->getPriority() > surface->getPriority()) {
- insertIndex = index;
- break;
+ if (surface) {
+ int index = 0, insertIndex = -1;
+ for (Common::Array<BaseSurface*>::iterator iter = _surfaces.begin(); iter != _surfaces.end(); iter++) {
+ if ((*iter)->getPriority() > surface->getPriority()) {
+ insertIndex = index;
+ break;
+ }
+ index++;
}
- index++;
+ if (insertIndex >= 0)
+ _surfaces.insert_at(insertIndex, surface);
+ else
+ _surfaces.push_back(surface);
}
- if (insertIndex >= 0)
- _surfaces.insert_at(insertIndex, surface);
- else
- _surfaces.push_back(surface);
}
bool Scene::removeSurface(BaseSurface *surface) {
@@ -191,7 +192,7 @@ Sprite *Scene::insertStaticSprite(uint32 fileHash, int surfacePriority) {
return addSprite(new StaticSprite(_vm, fileHash, surfacePriority));
}
-void Scene::insertMouse433(uint32 fileHash, NRect *mouseRect) {
+void Scene::insertMouse433(uint32 fileHash, const NRect *mouseRect) {
NRect rect(-1, -1, -1, -1);
if (mouseRect)
rect = *mouseRect;
diff --git a/engines/neverhood/scene.h b/engines/neverhood/scene.h
index c9e27f7bb4..21f054e123 100644
--- a/engines/neverhood/scene.h
+++ b/engines/neverhood/scene.h
@@ -59,7 +59,7 @@ public:
void setPalette(uint32 fileHash = 0);
void setHitRects(uint32 id);
Sprite *insertStaticSprite(uint32 fileHash, int surfacePriority);
- void insertMouse433(uint32 fileHash, NRect *mouseRect = NULL);
+ void insertMouse433(uint32 fileHash, const NRect *mouseRect = NULL);
void insertMouse435(uint32 fileHash, int16 x1, int16 x2);
void insertNavigationMouse(uint32 fileHash, int type);
void showMouse(bool visible);