Initial commit

This commit is contained in:
2026-02-02 04:50:13 +01:00
commit 5b11698731
22592 changed files with 7677434 additions and 0 deletions

View File

@@ -0,0 +1,250 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#include "engines/stark/ui/world/actionmenu.h"
#include "engines/stark/ui/cursor.h"
#include "engines/stark/ui/world/gamewindow.h"
#include "engines/stark/ui/world/inventorywindow.h"
#include "engines/stark/gfx/driver.h"
#include "engines/stark/resources/anim.h"
#include "engines/stark/resources/item.h"
#include "engines/stark/resources/knowledgeset.h"
#include "engines/stark/resources/level.h"
#include "engines/stark/resources/pattable.h"
#include "engines/stark/resources/sound.h"
#include "engines/stark/services/services.h"
#include "engines/stark/services/gameinterface.h"
#include "engines/stark/services/staticprovider.h"
#include "engines/stark/services/global.h"
#include "engines/stark/scene.h"
#include "engines/stark/visual/image.h"
#include "engines/stark/visual/text.h"
namespace Stark {
static const int kAutoCloseSuspended = -1;
static const int kAutoCloseDisabled = -2;
static const int kAutoCloseDelay = 200;
ActionMenu::ActionMenu(Gfx::Driver *gfx, Cursor *cursor) :
Window(gfx, cursor),
_fromInventory(false),
_itemDescription(nullptr),
_item(nullptr),
_inventory(nullptr),
_activeMenuType(kActionNoneM),
_autoCloseTimeRemaining(kAutoCloseDisabled) {
_background = StarkStaticProvider->getUIElement(StaticProvider::kActionMenuBg);
_itemDescription = new VisualText(gfx);
_itemDescription->setColor(Gfx::Color(0xFF, 0xFF, 0xFF));
_itemDescription->setBackgroundColor(Gfx::Color(0x00, 0x00, 0x00, 0x80));
_itemDescription->setFont(FontProvider::kSmallFont);
_itemDescription->setTargetWidth(96);
_buttons[kActionHand].action = Resources::PATTable::kActionUse;
_buttons[kActionHand].rect = Common::Rect(90, 15, 126, 63);
_buttons[kActionEye].action = Resources::PATTable::kActionLook;
_buttons[kActionEye].rect = Common::Rect(5, 77, 51, 110);
_buttons[kActionMouth].action = Resources::PATTable::kActionTalk;
_buttons[kActionMouth].rect = Common::Rect(42, 35, 83, 74);
_actionMouthHoverSound = StarkStaticProvider->getUISound(StaticProvider::kActionMouthHover);
_actionMouthHoverSound->setLooping(false);
_actionHoverSound = StarkStaticProvider->getUISound(StaticProvider::kActionHover);
clearActions();
}
ActionMenu::~ActionMenu() {
delete _itemDescription;
}
void ActionMenu::open(Resources::ItemVisual *item, const Common::Point &itemRelativePos) {
_visible = true;
Common::Point mousePos = _cursor->getMousePosition();
_position = computePosition(mousePos);
_itemRelativePos = itemRelativePos;
_item = item;
_fromInventory = item->getSubType() == Resources::Item::kItemInventory;
if (_fromInventory) {
_itemDescription->setText(StarkGameInterface->getItemTitle(item));
} else {
_itemDescription->setText(StarkGameInterface->getItemTitleAt(item, itemRelativePos));
}
_cursor->setMouseHint("");
clearActions();
Resources::ActionArray possible;
if (_fromInventory) {
possible = StarkGameInterface->listActionsPossibleForObject(_item);
} else {
possible = StarkGameInterface->listActionsPossibleForObjectAt(_item, _itemRelativePos);
}
for (uint i = 0; i < possible.size(); i++) {
enableAction(possible[i]);
}
if (_fromInventory) {
// All inventory items can be picked up
enableAction(Resources::PATTable::kActionUse);
}
}
void ActionMenu::close() {
_visible = false;
_item = nullptr;
_activeMenuType = kActionNoneM;
_actionHoverSound->stop();
}
Common::Rect ActionMenu::computePosition(const Common::Point &mouse) const {
Common::Rect position = Common::Rect::center(mouse.x, mouse.y, 160, 111);
Common::Rect gameWindowRect(Gfx::Driver::kGameViewportWidth, Gfx::Driver::kGameViewportHeight);
gameWindowRect.translate(0, Gfx::Driver::kTopBorderHeight);
if (position.top < gameWindowRect.top) position.translate(0, gameWindowRect.top - position.top);
if (position.left < gameWindowRect.left) position.translate(gameWindowRect.left - position.left, 0);
if (position.bottom > gameWindowRect.bottom) position.translate(0, gameWindowRect.bottom - position.bottom);
if (position.right > gameWindowRect.right) position.translate(gameWindowRect.right - position.right, 0);
return position;
}
void ActionMenu::onRender() {
_background->render(Common::Point(0, 0), false);
for (uint i = 0; i < ARRAYSIZE(_buttons); i++) {
if (_buttons[i].enabled) {
VisualImageXMG *visual = StarkGameInterface->getActionImage(_buttons[i].action, (int32)i == _activeMenuType);
visual->render(Common::Point(_buttons[i].rect.left, _buttons[i].rect.top), false);
}
}
Common::Rect descriptionSize = _itemDescription->getRect();
int descriptionX = 60 + (_itemDescription->getTargetWidth() - descriptionSize.width()) / 2;
int descriptionY = _position.height() - descriptionSize.height();
_itemDescription->render(Common::Point(descriptionX, descriptionY));
}
void ActionMenu::clearActions() {
for (uint i = 0; i < ARRAYSIZE(_buttons); i++) {
_buttons[i].enabled = false;
}
}
void ActionMenu::enableAction(uint32 action) {
for (uint j = 0; j < ARRAYSIZE(_buttons); j++) {
if (_buttons[j].action == action) {
_buttons[j].enabled = true;
break;
}
}
}
void ActionMenu::updateActionSound() {
if (_activeMenuType == kActionNoneM) {
_actionHoverSound->stop();
return;
}
_actionHoverSound->play();
if (_activeMenuType == kActionMouth) {
_actionMouthHoverSound->play();
}
}
void ActionMenu::onMouseMove(const Common::Point &pos) {
int32 prevActive = _activeMenuType;
int32 newActive = kActionNoneM;
for (uint i = 0; i < ARRAYSIZE(_buttons); i++) {
if (_buttons[i].enabled && _buttons[i].rect.contains(pos)) {
newActive = i;
}
}
if (newActive != prevActive) {
_activeMenuType = newActive;
if (_activeMenuType == kActionNoneM) {
_cursor->setCursorType(Cursor::kDefault);
} else {
_cursor->setCursorType(Cursor::kActive);
}
updateActionSound();
}
_autoCloseTimeRemaining = kAutoCloseSuspended;
}
void ActionMenu::onClick(const Common::Point &pos) {
assert(_item);
for (uint i = 0; i < ARRAYSIZE(_buttons); i++) {
if (_buttons[i].enabled && _buttons[i].rect.contains(pos)) {
if (_fromInventory && i == kActionHand) {
_inventory->setSelectedInventoryItem(_item->getIndex());
} else {
if (_fromInventory) {
StarkGameInterface->itemDoAction(_item, _buttons[i].action);
} else {
StarkGameInterface->itemDoActionAt(_item, _buttons[i].action, _itemRelativePos);
}
}
close();
break;
}
}
}
void ActionMenu::setInventory(InventoryWindow *inventory) {
_inventory = inventory;
}
void ActionMenu::onGameLoop() {
if (!isMouseInside() && _autoCloseTimeRemaining == kAutoCloseSuspended) {
_autoCloseTimeRemaining = kAutoCloseDelay;
} else if (_autoCloseTimeRemaining >= 0) {
_autoCloseTimeRemaining -= StarkGlobal->getMillisecondsPerGameloop();
if (_autoCloseTimeRemaining <= 0) {
_autoCloseTimeRemaining = kAutoCloseSuspended;
close();
}
}
}
void ActionMenu::onScreenChanged() {
_itemDescription->reset();
}
} // End of namespace Stark

View File

@@ -0,0 +1,99 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef STARK_UI_ACTIONMENU_H
#define STARK_UI_ACTIONMENU_H
#include "engines/stark/ui/window.h"
namespace Stark {
class Cursor;
class VisualImageXMG;
class VisualText;
class InventoryWindow;
class GameWindow;
namespace Resources {
class ItemVisual;
class Sound;
}
class ActionMenu : public Window {
public:
ActionMenu(Gfx::Driver *gfx, Cursor *cursor);
~ActionMenu() override;
void setInventory(InventoryWindow *inventory);
void open(Resources::ItemVisual *item, const Common::Point &itemRelativePos);
void close();
void onScreenChanged();
protected:
Common::Rect computePosition(const Common::Point &mouse) const;
void onMouseMove(const Common::Point &pos) override;
void onClick(const Common::Point &pos) override;
void onGameLoop() override;
void onRender() override;
private:
void clearActions();
void enableAction(uint32 action);
void updateActionSound();
enum ActionMenuType {
kActionNoneM = -1,
kActionHand = 0,
kActionEye = 1,
kActionMouth = 2
};
struct ActionButton {
bool enabled;
uint32 action;
Common::Rect rect;
};
bool _fromInventory;
ActionButton _buttons[3];
VisualImageXMG *_background;
VisualText *_itemDescription;
Common::Point _itemRelativePos;
Resources::ItemVisual *_item;
InventoryWindow *_inventory;
int32 _autoCloseTimeRemaining;
int32 _activeMenuType;
Resources::Sound *_actionMouthHoverSound;
Resources::Sound *_actionHoverSound;
};
} // End of namespace Stark
#endif

View File

@@ -0,0 +1,129 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#include "engines/stark/ui/world/button.h"
#include "engines/stark/services/services.h"
#include "engines/stark/gfx/driver.h"
#include "engines/stark/visual/explodingimage.h"
#include "engines/stark/visual/flashingimage.h"
#include "engines/stark/visual/image.h"
#include "engines/stark/visual/text.h"
namespace Stark {
Button::Button(const Common::String &text, StaticProvider::UIElement stockElement, const Common::Point &pos, HintAlign align, const Common::Point &hintPos) :
_position(pos),
_stockElement(stockElement),
_text(text),
_hintPosition(hintPos),
_align(align),
_mouseText(nullptr),
_renderHint(false),
_explodingImageAnimation(nullptr),
_flashingImageAnimation(nullptr) {
}
Button::~Button() {
delete _explodingImageAnimation;
delete _flashingImageAnimation;
delete _mouseText;
}
void Button::render() {
VisualImageXMG *image = StarkStaticProvider->getUIElement(_stockElement);
image->render(_position, false);
if (_explodingImageAnimation) {
_explodingImageAnimation->render(_position);
}
if (_flashingImageAnimation) {
_flashingImageAnimation->render(_position);
}
if (_renderHint) {
Common::Point pos(_hintPosition);
if (_align == kAlignRight) {
pos.x -= _mouseText->getRect().width();
}
_mouseText->render(pos);
_renderHint = false;
}
}
bool Button::containsPoint(const Common::Point &point) {
VisualImageXMG *image = StarkStaticProvider->getUIElement(_stockElement);
Common::Rect r;
r.left = _position.x;
r.top = _position.y;
r.setWidth(image->getWidth());
r.setHeight(image->getHeight());
return r.contains(point);
}
void Button::showButtonHint() {
if (!_mouseText) {
_mouseText = new VisualText(StarkGfx);
_mouseText->setText(_text);
_mouseText->setColor(Gfx::Color(0xFF, 0xFF, 0xFF));
_mouseText->setFont(FontProvider::kSmallFont);
_mouseText->setTargetWidth(96);
}
_renderHint = true;
}
void Button::resetHintVisual() {
delete _mouseText;
_mouseText = nullptr;
}
void Button::goToAnimStatement(int animScriptItemIndex) {
StarkStaticProvider->goToAnimScriptStatement(_stockElement, animScriptItemIndex);
}
void Button::startImageExplosion(VisualImageXMG *image) {
assert(image);
stopImageExplosion();
_explodingImageAnimation = new VisualExplodingImage(StarkGfx);
_explodingImageAnimation->initFromSurface(image->getSurface(), image->getWidth(), image->getHeight());
}
void Button::stopImageExplosion() {
delete _explodingImageAnimation;
_explodingImageAnimation = nullptr;
}
void Button::startImageFlashing(VisualImageXMG *image) {
assert(image);
stopImageFlashing();
_flashingImageAnimation = new VisualFlashingImage(StarkGfx);
_flashingImageAnimation->initFromSurface(image->getSurface(), image->getWidth(), image->getHeight());
}
void Button::stopImageFlashing() {
delete _flashingImageAnimation;
_flashingImageAnimation = nullptr;
}
} // End of namespace Stark

View File

@@ -0,0 +1,89 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef STARK_UI_BUTTON_H
#define STARK_UI_BUTTON_H
#include "engines/stark/services/staticprovider.h"
#include "common/scummsys.h"
#include "common/rect.h"
#include "common/str.h"
namespace Stark {
class VisualExplodingImage;
class VisualFlashingImage;
class VisualImageXMG;
class VisualText;
namespace Resources {
class Anim;
}
class Button {
public:
enum HintAlign { kAlignLeft, kAlignRight };
Button(const Common::String &text, StaticProvider::UIElement stockElement, const Common::Point &pos, HintAlign align, const Common::Point &hintPos);
~Button();
void setPosition(const Common::Point &pos) { _position = pos; }
void setUIElement(const StaticProvider::UIElement &stockElement) { _stockElement = stockElement; }
/** Set hint to render for one frame */
void showButtonHint();
void render();
bool containsPoint(const Common::Point &point);
/** Reset the hint text visual so it is rebuilt with the appropriate size */
void resetHintVisual();
/** Move execution of the button's icon anim script to the specified item */
void goToAnimStatement(int animScriptItemIndex);
/** Start overlaying an explosion animation of an image on top of the button */
void startImageExplosion(VisualImageXMG *image);
/** Remove the currently playing exploding image animation, if any */
void stopImageExplosion();
/** Start a flash animation of an image button */
void startImageFlashing(VisualImageXMG *image);
/** Remove the currently playing flash image animation, if any */
void stopImageFlashing();
private:
StaticProvider::UIElement _stockElement;
Common::Point _position;
Common::Point _hintPosition;
Common::String _text;
VisualText *_mouseText;
VisualExplodingImage *_explodingImageAnimation;
VisualFlashingImage *_flashingImageAnimation;
const HintAlign _align;
bool _renderHint;
};
} // End of namespace Stark
#endif // STARK_UI_BUTTON_H

View File

@@ -0,0 +1,63 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#include "engines/stark/ui/world/clicktext.h"
#include "engines/stark/services/services.h"
#include "engines/stark/visual/text.h"
namespace Stark {
ClickText::ClickText(const Common::String &text, const Gfx::Color &color) :
_text(text),
_color(color) {
_visualPassive = new VisualText(StarkGfx);
_visualPassive->setText(_text);
_visualPassive->setColor(_color);
_visualPassive->setFont(FontProvider::kBigFont);
_visualPassive->setTargetWidth(600);
_visualActive = new VisualText(StarkGfx);
_visualActive->setText(_text);
_visualActive->setColor(Gfx::Color(0x00, 0x00, 0x00));
_visualActive->setBackgroundColor(_color);
_visualActive->setFont(FontProvider::kBigFont);
_visualActive->setTargetWidth(600);
_curVisual = _visualPassive;
_bbox = _curVisual->getRect();
}
ClickText::~ClickText() {
delete _visualActive;
delete _visualPassive;
}
void ClickText::render() {
_curVisual->render(_position);
}
bool ClickText::containsPoint(const Common::Point &point) const {
Common::Rect r = _bbox;
r.translate(_position.x, _position.y);
return r.contains(point);
}
} // End of namespace Stark

View File

@@ -0,0 +1,60 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef STARK_UI_CLICK_TEXT_H
#define STARK_UI_CLICK_TEXT_H
#include "engines/stark/gfx/color.h"
#include "common/scummsys.h"
#include "common/rect.h"
#include "common/str.h"
namespace Stark {
class VisualText;
class ClickText {
public:
ClickText(const Common::String &text, const Gfx::Color &color);
~ClickText();
void setPosition(const Common::Point &pos) { _position = pos; }
void render();
bool containsPoint(const Common::Point &point) const;
int getHeight() const { return _bbox.height(); }
void setActive() { _curVisual = _visualActive; }
void setPassive() { _curVisual = _visualPassive; }
private:
VisualText *_visualPassive;
VisualText *_visualActive;
VisualText *_curVisual;
Common::Point _position;
Common::String _text;
Common::Rect _bbox;
Gfx::Color _color;
};
} // End of namespace Stark
#endif // STARK_UI_CLICK_TEXT_H

View File

@@ -0,0 +1,382 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#include "engines/stark/ui/world/dialogpanel.h"
#include "engines/stark/gfx/driver.h"
#include "engines/stark/resources/speech.h"
#include "engines/stark/services/services.h"
#include "engines/stark/services/staticprovider.h"
#include "engines/stark/services/dialogplayer.h"
#include "engines/stark/services/settings.h"
#include "engines/stark/services/userinterface.h"
#include "engines/stark/ui/cursor.h"
#include "engines/stark/ui/world/clicktext.h"
#include "engines/stark/visual/image.h"
#include "engines/stark/visual/text.h"
namespace Stark {
DialogPanel::DialogPanel(Gfx::Driver *gfx, Cursor *cursor) :
Window(gfx, cursor),
_subtitleVisual(nullptr),
_currentSpeech(nullptr),
_scrollUpArrowVisible(false),
_scrollDownArrowVisible(false),
_firstVisibleOption(0),
_lastVisibleOption(0),
_focusedOption(0),
_acceptIdleMousePos(false) {
_position = Common::Rect(Gfx::Driver::kOriginalWidth, Gfx::Driver::kBottomBorderHeight);
_position.translate(0, Gfx::Driver::kTopBorderHeight + Gfx::Driver::kGameViewportHeight);
_visible = true;
_activeBackGroundImage = StarkStaticProvider->getUIElement(StaticProvider::kTextBackgroundActive);
_passiveBackGroundImage = StarkStaticProvider->getUIElement(StaticProvider::kTextBackgroundPassive);
_scrollUpArrowImage = StarkStaticProvider->getUIElement(StaticProvider::kTextScrollUpArrow);
_scrollDownArrowImage = StarkStaticProvider->getUIElement(StaticProvider::kTextScrollDownArrow);
_dialogOptionBullet = StarkStaticProvider->getUIImage(StaticProvider::kDialogOptionBullet);
_scrollUpArrowRect = Common::Rect(_scrollUpArrowImage->getWidth(), _scrollUpArrowImage->getHeight());
_scrollUpArrowRect.translate(0, _optionsTop);
_scrollDownArrowRect = Common::Rect(_scrollDownArrowImage->getWidth(), _scrollDownArrowImage->getHeight());
_scrollDownArrowRect.translate(0, _optionsTop + _optionsHeight - _scrollDownArrowImage->getHeight() - 9);
}
DialogPanel::~DialogPanel() {
clearOptions();
clearSubtitleVisual();
}
void DialogPanel::abortCurrentSpeech() {
if (_currentSpeech) {
_currentSpeech->stop();
_currentSpeech = nullptr;
}
}
void DialogPanel::clearSubtitleVisual() {
delete _subtitleVisual;
_subtitleVisual = nullptr;
}
void DialogPanel::clearOptions() {
for (uint i = 0; i < _options.size(); i++) {
delete _options[i];
}
_options.clear();
}
void DialogPanel::renderOptions() {
uint32 pos = _optionsTop;
for (uint i = _firstVisibleOption; i <= _lastVisibleOption; ++i) {
_options[i]->setPosition(Common::Point(_optionsLeft, pos));
_options[i]->render();
_dialogOptionBullet->render(Common::Point(_optionsLeft - 13, pos + 3), false);
pos += _options[i]->getHeight();
}
_scrollUpArrowVisible = _firstVisibleOption > 0;
_scrollDownArrowVisible = _lastVisibleOption < _options.size() - 1;
}
void DialogPanel::renderScrollArrows() const {
if (_scrollUpArrowVisible) {
_scrollUpArrowImage->render(Common::Point(_scrollUpArrowRect.left, _scrollUpArrowRect.top), true);
}
if (_scrollDownArrowVisible) {
_scrollDownArrowImage->render(Common::Point(_scrollDownArrowRect.left, _scrollDownArrowRect.top), true);
}
}
void DialogPanel::onGameLoop() {
// Clear completed speeches
if (!_currentSpeech || !_currentSpeech->isPlaying()) {
_currentSpeech = nullptr;
clearSubtitleVisual();
// Toggle subtitles on and off when requested
if (StarkUserInterface->hasToggleSubtitleRequest()) {
StarkUserInterface->performToggleSubtitle();
}
}
// Update the dialog engine
StarkDialogPlayer->update();
// Check if a new speech can be played
if (StarkDialogPlayer->isSpeechReady()) {
_currentSpeech = StarkDialogPlayer->acquireReadySpeech();
_currentSpeech->playSound();
updateSubtitleVisual();
}
if (_options.empty() && StarkDialogPlayer->areOptionsAvailable()) {
updateDialogOptions();
}
}
void DialogPanel::onRender() {
// Draw options if available
if (!_options.empty()) {
_activeBackGroundImage->render(Common::Point(0, 0), false);
renderOptions();
renderScrollArrows();
} else {
_passiveBackGroundImage->render(Common::Point(0, 0), false);
// Draw subtitle if available
if (_subtitleVisual && StarkSettings->getBoolSetting(Settings::kSubtitle)) {
_subtitleVisual->render(Common::Point(_optionsLeft, _optionsTop));
}
}
}
void DialogPanel::updateSubtitleVisual() {
clearSubtitleVisual();
Gfx::Color color = _otherColor;
if (_currentSpeech->characterIsApril())
color = _aprilColor;
_subtitleVisual = new VisualText(_gfx);
_subtitleVisual->setText(_currentSpeech->getPhrase());
_subtitleVisual->setAlign(Graphics::TextAlign::kTextAlignStart);
_subtitleVisual->setColor(color);
_subtitleVisual->setFont(FontProvider::kBigFont);
_subtitleVisual->setTargetWidth(600);
}
void DialogPanel::updateDialogOptions() {
clearOptions();
_firstVisibleOption = 0;
_lastVisibleOption = 0;
_focusedOption = 0;
Common::Array<DialogPlayer::Option> options = StarkDialogPlayer->listOptions();
for (uint i = 0; i < options.size(); i++) {
_options.push_back(new ClickText(options[i]._caption, _aprilColor));
}
if (!_options.empty()) {
updateLastVisibleOption();
_options[_focusedOption]->setActive();
_acceptIdleMousePos = true;
}
}
void DialogPanel::onMouseMove(const Common::Point &pos) {
static Common::Point prevPos;
if (_subtitleVisual) {
_cursor->setCursorType(Cursor::kDefault);
} else if (!_options.empty()) {
if (pos != prevPos || _acceptIdleMousePos) {
for (uint i = _firstVisibleOption; i <= _lastVisibleOption; ++i) {
if (_options[i]->containsPoint(pos)) {
_options[_focusedOption]->setPassive();
_focusedOption = i;
_options[_focusedOption]->setActive();
_cursor->setCursorType(Cursor::kActive);
_acceptIdleMousePos = false;
prevPos = pos;
return;
}
}
}
if (_options[_focusedOption]->containsPoint(pos)) {
_cursor->setCursorType(Cursor::kActive);
} else if (_scrollUpArrowVisible && _scrollUpArrowRect.contains(pos)) {
_cursor->setCursorType(Cursor::kActive);
} else if (_scrollDownArrowVisible && _scrollDownArrowRect.contains(pos)) {
_cursor->setCursorType(Cursor::kActive);
} else {
_cursor->setCursorType(Cursor::kDefault);
}
} else {
_cursor->setCursorType(Cursor::kDefault);
}
prevPos = pos;
}
void DialogPanel::onClick(const Common::Point &pos) {
if (!_options.empty()) {
if (_options[_focusedOption]->containsPoint(pos)) {
selectFocusedOption();
}
if (_scrollUpArrowVisible && _scrollUpArrowRect.contains(pos)) {
scrollUp();
}
if (_scrollDownArrowVisible && _scrollDownArrowRect.contains(pos)) {
scrollDown();
}
}
}
void DialogPanel::onRightClick(const Common::Point &pos) {
if (_currentSpeech && _currentSpeech->isPlaying()) {
abortCurrentSpeech();
clearSubtitleVisual();
}
}
void DialogPanel::reset() {
abortCurrentSpeech();
clearSubtitleVisual();
clearOptions();
StarkDialogPlayer->reset();
}
void DialogPanel::scrollUp() {
if (!_scrollUpArrowVisible) return;
_lastVisibleOption = _firstVisibleOption;
updateFirstVisibleOption();
_options[_focusedOption]->setPassive();
_focusedOption = _lastVisibleOption;
_options[_focusedOption]->setActive();
}
void DialogPanel::scrollDown() {
if (!_scrollDownArrowVisible) return;
_firstVisibleOption = _lastVisibleOption;
updateLastVisibleOption();
_options[_focusedOption]->setPassive();
_focusedOption = _firstVisibleOption;
_options[_focusedOption]->setActive();
}
void DialogPanel::focusNextOption() {
if (_options.empty() || _focusedOption == _options.size() - 1) return;
_options[_focusedOption]->setPassive();
++_focusedOption;
_options[_focusedOption]->setActive();
if (_focusedOption > _lastVisibleOption) {
_lastVisibleOption = _focusedOption;
updateFirstVisibleOption();
}
}
void DialogPanel::focusPrevOption() {
if (_options.empty() || _focusedOption == 0) return;
_options[_focusedOption]->setPassive();
--_focusedOption;
_options[_focusedOption]->setActive();
if (_focusedOption < _firstVisibleOption) {
_firstVisibleOption = _focusedOption;
updateLastVisibleOption();
}
}
void DialogPanel::selectFocusedOption() {
if (_options.size() > 0) {
StarkDialogPlayer->selectOption(_focusedOption);
clearOptions();
}
}
void DialogPanel::selectOption(uint index) {
if (_options.size() <= index) return;
StarkDialogPlayer->selectOption(index);
clearOptions();
}
void DialogPanel::onScreenChanged() {
if (_currentSpeech) {
updateSubtitleVisual();
} else {
updateDialogOptions();
}
}
void DialogPanel::updateFirstVisibleOption() {
_firstVisibleOption = _lastVisibleOption;
uint32 height = _optionsTop + _options[_lastVisibleOption]->getHeight();
while (_firstVisibleOption > 0) {
height += _options[_firstVisibleOption - 1]->getHeight();
if (height <= _optionsHeight) {
--_firstVisibleOption;
} else {
break;
}
}
if (_firstVisibleOption == 0) {
while (_lastVisibleOption < _options.size() - 1) {
height += _options[_lastVisibleOption + 1]->getHeight();
if (height <= _optionsHeight) {
++_lastVisibleOption;
} else {
break;
}
}
}
}
void DialogPanel::updateLastVisibleOption() {
_lastVisibleOption = _firstVisibleOption;
uint32 height = _optionsTop + _options[_firstVisibleOption]->getHeight();
while (_lastVisibleOption < _options.size() - 1) {
height += _options[_lastVisibleOption + 1]->getHeight();
if (height <= _optionsHeight) {
++_lastVisibleOption;
} else {
break;
}
}
if (_lastVisibleOption == _options.size() - 1) {
while (_firstVisibleOption > 0) {
height += _options[_firstVisibleOption - 1]->getHeight();
if (height <= _optionsHeight) {
--_firstVisibleOption;
} else {
break;
}
}
}
}
} // End of namespace Stark

View File

@@ -0,0 +1,116 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef STARK_UI_DIALOG_PANEL_H
#define STARK_UI_DIALOG_PANEL_H
#include "engines/stark/ui/window.h"
#include "engines/stark/gfx/color.h"
#include "common/scummsys.h"
#include "common/str.h"
#include "common/str-array.h"
#include "common/array.h"
#include "common/rect.h"
namespace Stark {
class VisualImageXMG;
class VisualText;
class ClickText;
namespace Resources {
class Speech;
}
class DialogPanel : public Window {
public:
DialogPanel(Gfx::Driver *gfx, Cursor *cursor);
virtual ~DialogPanel();
/** Abort the currently playing dialog */
void reset();
/** The screen resolution changed, rebuild the text accordingly */
void onScreenChanged();
/** Scroll up and down the panel */
void scrollUp();
void scrollDown();
/** Select the next or previous option */
void focusNextOption();
void focusPrevOption();
/** Select the focused option */
void selectFocusedOption();
/** Select an option by index */
void selectOption(uint index);
protected:
void onMouseMove(const Common::Point &pos) override;
void onClick(const Common::Point &pos) override;
void onRightClick(const Common::Point &pos) override;
void onGameLoop() override;
void onRender() override;
private:
void updateSubtitleVisual();
void clearSubtitleVisual();
void updateDialogOptions();
void clearOptions();
void renderOptions();
void renderScrollArrows() const;
void updateFirstVisibleOption();
void updateLastVisibleOption();
VisualImageXMG *_passiveBackGroundImage;
VisualImageXMG *_activeBackGroundImage;
VisualImageXMG *_scrollUpArrowImage;
VisualImageXMG *_scrollDownArrowImage;
VisualImageXMG *_dialogOptionBullet;
VisualText *_subtitleVisual;
bool _scrollUpArrowVisible;
bool _scrollDownArrowVisible;
Common::Rect _scrollUpArrowRect;
Common::Rect _scrollDownArrowRect;
Resources::Speech *_currentSpeech;
void abortCurrentSpeech();
uint32 _firstVisibleOption, _lastVisibleOption;
uint32 _focusedOption;
Common::Array<ClickText*> _options;
bool _acceptIdleMousePos;
const Gfx::Color _aprilColor = Gfx::Color(0xFF, 0xC0, 0x00);
const Gfx::Color _otherColor = Gfx::Color(0xFF, 0x40, 0x40);
static const uint32 _optionsTop = 4;
static const uint32 _optionsLeft = 30;
static const uint32 _optionsHeight = 80;
};
} // End of namespace Stark
#endif // STARK_UI_DIALOG_PANEL_H

View File

@@ -0,0 +1,116 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#include "common/rect.h"
#include "engines/stark/ui/world/fmvscreen.h"
#include "engines/stark/gfx/driver.h"
#include "engines/stark/gfx/surfacerenderer.h"
#include "engines/stark/gfx/bitmap.h"
#include "engines/stark/services/archiveloader.h"
#include "engines/stark/services/services.h"
#include "engines/stark/services/userinterface.h"
#include "engines/stark/services/settings.h"
namespace Stark {
FMVScreen::FMVScreen(Gfx::Driver *gfx, Cursor *cursor) :
SingleWindowScreen(Screen::kScreenFMV, gfx, cursor) {
_position = Common::Rect(Gfx::Driver::kOriginalWidth, Gfx::Driver::kOriginalHeight);
_visible = true;
_bitmap = _gfx->createBitmap();
_bitmap->setSamplingFilter(StarkSettings->getImageSamplingFilter());
_decoder = new Video::BinkDecoder();
_decoder->setSoundType(Audio::Mixer::kSFXSoundType);
_surfaceRenderer = _gfx->createSurfaceRenderer();
}
FMVScreen::~FMVScreen() {
delete _decoder;
delete _bitmap;
delete _surfaceRenderer;
}
void FMVScreen::play(const Common::Path &name) {
Common::SeekableReadStream *stream = nullptr;
// Play the low-resolution video, if possible
if (!StarkSettings->getBoolSetting(Settings::kHighFMV) && StarkSettings->hasLowResFMV()) {
Common::String lowResBaseName = name.baseName();
lowResBaseName.erase(lowResBaseName.size() - 4);
lowResBaseName += "_lo_res.bbb";
Common::Path lowResName(name.getParent().appendComponent(lowResBaseName));
stream = StarkArchiveLoader->getExternalFile(lowResName, "Global/");
if (!stream) {
debug("Could not open %s", lowResName.toString().c_str());
}
}
// Play the original video
if (!stream) {
stream = StarkArchiveLoader->getExternalFile(name, "Global/");
}
if (!stream) {
warning("Could not open %s", name.toString().c_str());
return;
}
_decoder->loadStream(stream);
if (!_decoder->isVideoLoaded()) {
error("Could not open %s", name.toString().c_str());
}
_decoder->setOutputPixelFormat(_bitmap->getBestPixelFormat());
_decoder->start();
}
void FMVScreen::onGameLoop() {
if (isPlaying()) {
if (_decoder->needsUpdate()) {
const Graphics::Surface *decodedSurface = _decoder->decodeNextFrame();
_bitmap->update(decodedSurface);
}
} else {
stop();
}
}
void FMVScreen::onRender() {
_surfaceRenderer->render(_bitmap, Common::Point(0, Gfx::Driver::kTopBorderHeight),
Gfx::Driver::kGameViewportWidth, Gfx::Driver::kGameViewportHeight);
}
bool FMVScreen::isPlaying() {
return _decoder->isPlaying() && !_decoder->endOfVideo();
}
void FMVScreen::stop() {
_decoder->stop();
StarkUserInterface->onFMVStopped();
}
} // End of namespace Stark

View File

@@ -0,0 +1,67 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef STARK_UI_FMV_PLAYER_H
#define STARK_UI_FMV_PLAYER_H
#include "engines/stark/ui/screen.h"
#include "engines/stark/ui/window.h"
#include "video/bink_decoder.h"
namespace Video {
class BinkDecoder;
}
namespace Stark {
namespace Gfx {
class SurfaceRenderer;
class Bitmap;
}
/**
* FMV Player
*
* Handles the state of the currently running FMV.
*/
class FMVScreen : public SingleWindowScreen {
public:
FMVScreen(Gfx::Driver *gfx, Cursor *cursor);
virtual ~FMVScreen();
void play(const Common::Path &name);
void stop();
protected:
void onGameLoop() override;
void onRender() override;
private:
bool isPlaying();
Video::BinkDecoder *_decoder;
Gfx::SurfaceRenderer *_surfaceRenderer;
Gfx::Bitmap *_bitmap;
};
} // End of namespace Stark
#endif // STARK_UI_FMV_PLAYER_H

View File

@@ -0,0 +1,157 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#include "engines/stark/ui/world/gamescreen.h"
#include "engines/stark/services/services.h"
#include "engines/stark/services/userinterface.h"
#include "engines/stark/services/global.h"
#include "engines/stark/ui/cursor.h"
#include "engines/stark/ui/world/actionmenu.h"
#include "engines/stark/ui/world/dialogpanel.h"
#include "engines/stark/ui/world/gamewindow.h"
#include "engines/stark/ui/world/inventorywindow.h"
#include "engines/stark/ui/world/topmenu.h"
#include "engines/stark/resources/level.h"
#include "engines/stark/resources/location.h"
namespace Stark {
GameScreen::GameScreen(Gfx::Driver *gfx, Cursor *cursor) :
Screen(Screen::kScreenGame),
_gfx(gfx),
_cursor(cursor) {
_topMenu = new TopMenu(_gfx, _cursor);
_dialogPanel = new DialogPanel(_gfx, _cursor);
_actionMenu = new ActionMenu(_gfx, _cursor);
_inventoryWindow = new InventoryWindow(_gfx, _cursor, _actionMenu);
_actionMenu->setInventory(_inventoryWindow);
_gameWindow = new GameWindow(_gfx, _cursor, _actionMenu, _inventoryWindow);
_gameScreenWindows.push_back(_actionMenu);
_gameScreenWindows.push_back(_inventoryWindow);
_gameScreenWindows.push_back(_gameWindow);
_gameScreenWindows.push_back(_topMenu);
_gameScreenWindows.push_back(_dialogPanel);
}
GameScreen::~GameScreen() {
delete _gameWindow;
delete _actionMenu;
delete _topMenu;
delete _dialogPanel;
delete _inventoryWindow;
}
void GameScreen::open() {
pauseGame(false);
StarkUserInterface->freeGameScreenThumbnail();
}
void GameScreen::close() {
_cursor->setMouseHint("");
pauseGame(true);
StarkUserInterface->saveGameScreenThumbnail();
}
void GameScreen::handleGameLoop() {
for (int i = _gameScreenWindows.size() - 1; i >= 0; i--) {
_gameScreenWindows[i]->handleGameLoop();
}
}
void GameScreen::render() {
for (int i = _gameScreenWindows.size() - 1; i >= 0; i--) {
_gameScreenWindows[i]->render();
}
}
InventoryWindow *GameScreen::getInventoryWindow() const {
return _inventoryWindow;
}
void GameScreen::reset() {
_dialogPanel->reset();
_gameWindow->reset();
_inventoryWindow->reset();
_actionMenu->close();
}
GameWindow *GameScreen::getGameWindow() const {
return _gameWindow;
}
DialogPanel *GameScreen::getDialogPanel() const {
return _dialogPanel;
}
void GameScreen::handleMouseMove() {
dispatchEvent(&Window::handleMouseMove);
}
void GameScreen::handleClick() {
dispatchEvent(&Window::handleClick);
}
void GameScreen::handleRightClick() {
dispatchEvent(&Window::handleRightClick);
}
void GameScreen::handleDoubleClick() {
dispatchEvent(&Window::handleDoubleClick);
}
void GameScreen::dispatchEvent(WindowHandler handler) {
for (uint i = 0; i < _gameScreenWindows.size(); i++) {
if (_gameScreenWindows[i]->isMouseInside()) {
(*_gameScreenWindows[i].*handler)();
return;
}
}
}
void GameScreen::onScreenChanged() {
_cursor->onScreenChanged();
_dialogPanel->onScreenChanged();
_topMenu->onScreenChanged();
_gameWindow->onScreenChanged();
_actionMenu->onScreenChanged();
}
void GameScreen::notifyInventoryItemEnabled(uint16 itemIndex) {
_topMenu->notifyInventoryItemEnabled(itemIndex);
}
void GameScreen::notifyDiaryEntryEnabled() {
_topMenu->notifyDiaryEntryEnabled();
}
void GameScreen::pauseGame(bool pause) {
if (StarkGlobal->getLevel()) {
StarkGlobal->getLevel()->onEnginePause(pause);
}
if (StarkGlobal->getCurrent()) {
StarkGlobal->getCurrent()->getLevel()->onEnginePause(pause);
StarkGlobal->getCurrent()->getLocation()->onEnginePause(pause);
}
}
} // End of namespace Stark

View File

@@ -0,0 +1,94 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef STARK_UI_WORLD_GAME_SCREEN_H
#define STARK_UI_WORLD_GAME_SCREEN_H
#include "engines/stark/ui/screen.h"
namespace Stark {
class ActionMenu;
class Cursor;
class DialogPanel;
class GameWindow;
class InventoryWindow;
class TopMenu;
class Window;
/**
* Game world screen
*
* Container for all the game world windows
*/
class GameScreen : public Screen {
public:
GameScreen(Gfx::Driver *gfx, Cursor *cursor);
virtual ~GameScreen();
// Screen API
void open() override;
void close() override;
void handleGameLoop() override;
void render() override;
void onScreenChanged() override;
void handleMouseMove() override;
void handleClick() override;
void handleRightClick() override;
void handleDoubleClick() override;
/** Get individual windows */
InventoryWindow *getInventoryWindow() const;
GameWindow *getGameWindow() const;
DialogPanel *getDialogPanel() const;
/** Clear any location dependant state */
void reset();
/** A new item has been added to the player's inventory */
void notifyInventoryItemEnabled(uint16 itemIndex);
/** A new entry has been added to the player's diary */
void notifyDiaryEntryEnabled();
private:
Gfx::Driver *_gfx;
Cursor *_cursor;
// Game Screen windows
ActionMenu *_actionMenu;
DialogPanel *_dialogPanel;
InventoryWindow *_inventoryWindow;
TopMenu *_topMenu;
GameWindow *_gameWindow;
// Game screen windows array
Common::Array<Window *> _gameScreenWindows;
typedef void (Window::*WindowHandler)();
void dispatchEvent(WindowHandler handler);
void pauseGame(bool pause);
};
} // End of namespace Stark
#endif // STARK_UI_WORLD_GAME_SCREEN_H

View File

@@ -0,0 +1,290 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#include "engines/stark/ui/world/gamewindow.h"
#include "engines/stark/scene.h"
#include "engines/stark/gfx/driver.h"
#include "engines/stark/resources/anim.h"
#include "engines/stark/resources/knowledgeset.h"
#include "engines/stark/resources/image.h"
#include "engines/stark/resources/item.h"
#include "engines/stark/resources/location.h"
#include "engines/stark/resources/layer.h"
#include "engines/stark/services/global.h"
#include "engines/stark/services/services.h"
#include "engines/stark/services/staticprovider.h"
#include "engines/stark/services/gameinterface.h"
#include "engines/stark/services/userinterface.h"
#include "engines/stark/ui/cursor.h"
#include "engines/stark/ui/world/actionmenu.h"
#include "engines/stark/ui/world/inventorywindow.h"
#include "engines/stark/visual/text.h"
#include "engines/stark/visual/image.h"
namespace Stark {
GameWindow::GameWindow(Gfx::Driver *gfx, Cursor *cursor, ActionMenu *actionMenu, InventoryWindow *inventory) :
Window(gfx, cursor),
_actionMenu(actionMenu),
_inventory(inventory),
_objectUnderCursor(nullptr),
_displayExit(false) {
_position = Common::Rect(Gfx::Driver::kGameViewportWidth, Gfx::Driver::kGameViewportHeight);
_position.translate(0, Gfx::Driver::kTopBorderHeight);
_visible = true;
_fadeRenderer = _gfx->createFadeRenderer();
_exitArrow = StarkStaticProvider->getUIElement(StaticProvider::kExitArrow);
_exitArrowLeft = StarkStaticProvider->getUIElement(StaticProvider::kExitArrowLeft);
_exitArrowRight = StarkStaticProvider->getUIElement(StaticProvider::kExitArrowRight);
_exitLeftBoundary = 5;
_exitRightBoundary = Gfx::Driver::kGameViewportWidth - _exitArrowRight->getWidth() - 5;
}
GameWindow::~GameWindow() {
delete _fadeRenderer;
}
void GameWindow::onRender() {
// List the items to render
Resources::Location *location = StarkGlobal->getCurrent()->getLocation();
_renderEntries = location->listRenderEntries();
Gfx::LightEntryArray lightEntries = location->listLightEntries();
// Render all the scene items
Gfx::RenderEntryArray::iterator element = _renderEntries.begin();
while (element != _renderEntries.end()) {
// Draw the current element
(*element)->render(lightEntries);
// Go for the next one
element++;
}
if (_displayExit) {
Common::Array<Common::Point> exitPositions = StarkGameInterface->listExitPositions();
for (uint i = 0; i < exitPositions.size(); ++i) {
Common::Point pos = exitPositions[i];
VisualImageXMG *exitImage = nullptr;
if (pos.x < _exitLeftBoundary) {
pos.x = _exitLeftBoundary;
exitImage = _exitArrowLeft;
} else if (pos.x > _exitRightBoundary) {
pos.x = _exitRightBoundary;
exitImage = _exitArrowRight;
} else {
exitImage = _exitArrow;
}
exitImage->render(pos, false);
}
}
float fadeLevel = StarkScene->getFadeLevel();
if ((1.0f - fadeLevel) > 0.00001f) {
_fadeRenderer->render(fadeLevel);
}
}
void GameWindow::onMouseMove(const Common::Point &pos) {
_renderEntries = StarkGlobal->getCurrent()->getLocation()->listRenderEntries();
if (!StarkUserInterface->isInteractive()) {
_objectUnderCursor = nullptr;
_cursor->setCursorType(Cursor::kPassive);
_cursor->setMouseHint("");
return;
}
int16 selectedInventoryItem = _inventory->getSelectedInventoryItem();
int16 singlePossibleAction = -1;
bool defaultAction = false;
bool itemActive = false;
checkObjectAtPos(pos, selectedInventoryItem, singlePossibleAction, defaultAction);
if (selectedInventoryItem != -1 && !defaultAction) {
VisualImageXMG *cursorImage = StarkGameInterface->getCursorImage(selectedInventoryItem);
_cursor->setCursorImage(cursorImage);
itemActive = singlePossibleAction == selectedInventoryItem;
} else if (_objectUnderCursor) {
switch (singlePossibleAction) {
case -1:
_cursor->setCursorType(Cursor::kActive);
break;
case Resources::PATTable::kActionLook:
_cursor->setCursorType(Cursor::kEye);
break;
case Resources::PATTable::kActionTalk:
_cursor->setCursorType(Cursor::kMouth);
break;
case Resources::PATTable::kActionUse:
_cursor->setCursorType(Cursor::kHand);
break;
default:
VisualImageXMG *cursorImage = StarkGameInterface->getCursorImage(singlePossibleAction);
_cursor->setCursorImage(cursorImage);
break;
}
} else {
// Not an object
_cursor->setCursorType(Cursor::kDefault);
}
_cursor->setItemActive(itemActive);
Common::String mouseHint;
if (_objectUnderCursor) {
mouseHint = StarkGameInterface->getItemTitleAt(_objectUnderCursor, _objectRelativePosition);
}
_cursor->setMouseHint(mouseHint);
}
void GameWindow::onClick(const Common::Point &pos) {
if (!StarkGlobal->getCurrent()) {
return; // No level is loaded yet, interaction is impossible
}
if (!StarkUserInterface->isInteractive()) {
StarkUserInterface->markInteractionDenied();
return;
}
_actionMenu->close();
int16 selectedInventoryItem = _inventory->getSelectedInventoryItem();
int16 singlePossibleAction = -1;
bool defaultAction;
checkObjectAtPos(pos, selectedInventoryItem, singlePossibleAction, defaultAction);
if (_objectUnderCursor) {
if (singlePossibleAction != -1) {
StarkGameInterface->itemDoActionAt(_objectUnderCursor, singlePossibleAction, _objectRelativePosition);
} else if (selectedInventoryItem == -1) {
_actionMenu->open(_objectUnderCursor, _objectRelativePosition);
}
} else {
// The walk code expects unscaled absolute mouse coordinates
StarkGameInterface->walkTo(_cursor->getMousePosition(true));
}
}
void GameWindow::onRightClick(const Common::Point &pos) {
if (!StarkUserInterface->isInteractive()) {
return;
}
int16 selectedInventoryItem = _inventory->getSelectedInventoryItem();
if (selectedInventoryItem == -1) {
_inventory->open();
} else {
_inventory->setSelectedInventoryItem(-1);
}
}
void GameWindow::onDoubleClick(const Common::Point &pos) {
if (!StarkUserInterface->isInteractive()) {
StarkUserInterface->markInteractionDenied();
return;
}
if (StarkGameInterface->isAprilWalking()) {
StarkGameInterface->setAprilRunning();
}
}
void GameWindow::checkObjectAtPos(const Common::Point &pos, int16 selectedInventoryItem, int16 &singlePossibleAction, bool &isDefaultAction) {
_objectUnderCursor = nullptr;
singlePossibleAction = -1;
isDefaultAction = false;
Math::Ray ray = StarkScene->makeRayFromMouse(_cursor->getMousePosition(true));
Common::Rect cursorRect;
if (selectedInventoryItem != -1) {
cursorRect = _cursor->getHotRectangle();
cursorRect.translate(pos.x, pos.y);
}
// Render entries are sorted from the farthest to the camera to the nearest
// Loop in reverse order
for (int i = _renderEntries.size() - 1; i >= 0; i--) {
if (_renderEntries[i]->containsPoint(pos, _objectRelativePosition, cursorRect)
|| _renderEntries[i]->intersectRay(ray)) {
_objectUnderCursor = _renderEntries[i]->getOwner();
break;
}
}
if (!_objectUnderCursor || !StarkGameInterface->itemHasActionAt(_objectUnderCursor, _objectRelativePosition, -1)) {
// Only consider items with runnable scripts
_objectUnderCursor = nullptr;
return;
}
int32 defaultAction = StarkGameInterface->itemGetDefaultActionAt(_objectUnderCursor, _objectRelativePosition);
if (defaultAction != -1) {
// Use the default action if there is one
singlePossibleAction = defaultAction;
isDefaultAction = true;
} else if (selectedInventoryItem != -1) {
// Use the selected inventory item if there is one
if (StarkGameInterface->itemHasActionAt(_objectUnderCursor, _objectRelativePosition, selectedInventoryItem)) {
singlePossibleAction = selectedInventoryItem;
}
} else {
// Otherwise, use stock actions
Resources::ActionArray actionsPossible = StarkGameInterface->listStockActionsPossibleForObjectAt(
_objectUnderCursor, _objectRelativePosition);
if (actionsPossible.size() == 1) {
singlePossibleAction = actionsPossible[0];
}
}
}
void GameWindow::reset() {
_renderEntries.clear();
_objectUnderCursor = nullptr;
_objectRelativePosition.x = 0;
_objectRelativePosition.y = 0;
}
void GameWindow::onScreenChanged() {
// May be called when resources have not been loaded
if (!StarkGlobal->getCurrent()) {
return;
}
Resources::Location *location = StarkGlobal->getCurrent()->getLocation();
Common::Array<Resources::ImageText *> images = location->listChildrenRecursive<Resources::ImageText>(Resources::Image::kImageText);
for (uint i = 0; i < images.size(); i++) {
images[i]->resetVisual();
}
}
} // End of namespace Stark

View File

@@ -0,0 +1,78 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef STARK_UI_GAME_WINDOW_H
#define STARK_UI_GAME_WINDOW_H
#include "engines/stark/gfx/faderenderer.h"
#include "engines/stark/gfx/renderentry.h"
#include "engines/stark/ui/window.h"
#include "common/scummsys.h"
#include "common/rect.h"
#include "common/array.h"
namespace Stark {
class ActionMenu;
class InventoryWindow;
class GameWindow : public Window {
public:
GameWindow(Gfx::Driver *gfx, Cursor *cursor, ActionMenu *actionMenu, InventoryWindow *inventory);
virtual ~GameWindow();
/** Clear the location dependent state */
void reset();
/** Update when the screen resolution has changed */
void onScreenChanged();
/** Toggle the display of exit locations */
void toggleExitDisplay() { _displayExit = !_displayExit; }
protected:
void onMouseMove(const Common::Point &pos) override;
void onClick(const Common::Point &pos) override;
void onRightClick(const Common::Point &pos) override;
void onDoubleClick(const Common::Point &pos) override;
void onRender() override;
void checkObjectAtPos(const Common::Point &pos, int16 selectedInventoryItem, int16 &singlePossibleAction, bool &isDefaultAction);
ActionMenu *_actionMenu;
InventoryWindow *_inventory;
Gfx::RenderEntryArray _renderEntries;
Resources::ItemVisual *_objectUnderCursor;
Common::Point _objectRelativePosition;
Gfx::FadeRenderer *_fadeRenderer;
VisualImageXMG *_exitArrow, *_exitArrowLeft, *_exitArrowRight;
int _exitLeftBoundary, _exitRightBoundary;
bool _displayExit;
};
} // End of namespace Stark
#endif // STARK_UI_GAME_WINDOW_H

View File

@@ -0,0 +1,302 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#include "engines/stark/ui/world/inventorywindow.h"
#include "engines/stark/ui/cursor.h"
#include "engines/stark/ui/world/actionmenu.h"
#include "engines/stark/gfx/driver.h"
#include "engines/stark/resources/knowledgeset.h"
#include "engines/stark/resources/item.h"
#include "engines/stark/resources/pattable.h"
#include "engines/stark/services/global.h"
#include "engines/stark/services/services.h"
#include "engines/stark/services/staticprovider.h"
#include "engines/stark/services/gameinterface.h"
#include "engines/stark/visual/image.h"
namespace Stark {
static const int kAutoCloseSuspended = -1;
static const int kAutoCloseDisabled = -2;
static const int kAutoCloseDelay = 200;
InventoryWindow::InventoryWindow(Gfx::Driver *gfx, Cursor *cursor, ActionMenu *actionMenu) :
Window(gfx, cursor),
_actionMenu(actionMenu),
_firstVisibleSlot(0),
_selectedInventoryItem(-1),
_autoCloseTimeRemaining(kAutoCloseDisabled) {
// The window has the same size as the game window
_position = Common::Rect(Gfx::Driver::kGameViewportWidth, Gfx::Driver::kGameViewportHeight);
_position.translate(0, Gfx::Driver::kTopBorderHeight);
_backgroundImage = StarkStaticProvider->getUIImage(StaticProvider::kInventoryBg);
// Center the background in the window
_backgroundRect = Common::Rect(_backgroundImage->getWidth(), _backgroundImage->getHeight());
_backgroundRect.translate((_position.width() - _backgroundRect.width()) / 2,
(_position.height() - _backgroundRect.height()) / 2);
_scrollUpArrowImage = StarkStaticProvider->getUIElement(StaticProvider::kInventoryScrollUpArrow);
_scrollDownArrowImage = StarkStaticProvider->getUIElement(StaticProvider::kInventoryScrollDownArrow);
_scrollUpArrowRect = Common::Rect(_scrollUpArrowImage->getWidth(), _scrollUpArrowImage->getHeight());
_scrollUpArrowRect.translate(_backgroundRect.right - _scrollUpArrowRect.width(),
_backgroundRect.top + 2);
_scrollDownArrowRect = Common::Rect(_scrollDownArrowImage->getWidth(), _scrollDownArrowImage->getHeight());
_scrollDownArrowRect.translate(_backgroundRect.right - _scrollDownArrowRect.width(),
_backgroundRect.bottom - _scrollDownArrowRect.height() - 2);
}
void InventoryWindow::open() {
if (!_visible) {
_actionMenu->close();
}
_visible = true;
// The user needs to move the mouse over the background at least once
// before autoclose is enabled.
_autoCloseTimeRemaining = kAutoCloseDisabled;
}
void InventoryWindow::close() {
if (_visible) {
_actionMenu->close();
}
_visible = false;
}
void InventoryWindow::setSelectedInventoryItem(int16 selectedInventoryItem) {
// The first 4 elements are UI elements (Eye, Mouth, Hand, ...)
// Scripts pass 0 when they want to clear the selected inventory item
if (selectedInventoryItem < 4) {
_selectedInventoryItem = -1;
} else {
_selectedInventoryItem = selectedInventoryItem;
}
}
int16 InventoryWindow::getSelectedInventoryItem() const {
return _selectedInventoryItem;
}
Common::Rect InventoryWindow::getSlotRect(uint32 slot) const {
Common::Rect rect = Common::Rect(64, 64);
rect.translate(
96 * (slot % 5) + _backgroundRect.left + 24,
96 * (slot / 5) + _backgroundRect.left + 8); // The original uses left here as well
return rect;
}
Common::Rect InventoryWindow::getItemRect(uint32 slot, VisualImageXMG *image) const {
Common::Rect rect = getSlotRect(slot % _visibleSlotsCount);
// Center the image in the inventory slot
rect.translate((rect.width() - image->getWidth()) / 2,
(rect.height() - image->getHeight()) / 2);
return rect;
}
void InventoryWindow::onRender() {
_renderEntries = StarkGlobal->getInventory()->getInventoryRenderEntries();
_backgroundImage->render(Common::Point(_backgroundRect.left, _backgroundRect.top), false);
drawScrollArrows();
for (uint i = _firstVisibleSlot; i < _renderEntries.size() && isSlotVisible(i); i++) {
VisualImageXMG *image = _renderEntries[i]->getImage();
// Get the item rect
Common::Rect pos = getItemRect(i, image);
image->render(Common::Point(pos.left, pos.top), false);
}
}
void InventoryWindow::drawScrollArrows() const {
if (canScrollUp()) {
_scrollUpArrowImage->render(Common::Point(_scrollUpArrowRect.left, _scrollUpArrowRect.top), false);
}
if (canScrollDown()) {
_scrollDownArrowImage->render(Common::Point(_scrollDownArrowRect.left, _scrollDownArrowRect.top), false);
}
}
void InventoryWindow::checkObjectAtPos(Common::Point pos, Resources::ItemVisual **item, int16 selectedInventoryItem, int16 &singlePossibleAction) {
*item = nullptr;
singlePossibleAction = -1;
// Check for inventory mouse overs
for (uint i = _firstVisibleSlot; i < _renderEntries.size() && isSlotVisible(i); i++) {
VisualImageXMG *image = _renderEntries[i]->getImage();
Common::Rect itemRect = getItemRect(i, image);
if (itemRect.contains(pos)) {
*item = _renderEntries[i]->getOwner();
break;
}
}
if (!*item) {
// No item at specified position
return;
}
if (selectedInventoryItem == -1) {
Resources::ActionArray actionsPossible;
actionsPossible = StarkGameInterface->listStockActionsPossibleForObject(*item);
if (actionsPossible.empty()) {
// The item can still be taken
singlePossibleAction = Resources::PATTable::kActionUse;
}
} else {
if (StarkGameInterface->itemHasAction(*item, selectedInventoryItem)) {
singlePossibleAction = selectedInventoryItem;
}
}
}
void InventoryWindow::onMouseMove(const Common::Point &pos) {
Resources::ItemVisual *hoveredItem = nullptr;
int16 hoveredItemAction = -1;
checkObjectAtPos(pos, &hoveredItem, _selectedInventoryItem, hoveredItemAction);
if (_selectedInventoryItem == -1) {
if (hoveredItem) {
_cursor->setCursorType(Cursor::kActive);
} else if ((canScrollDown() && _scrollDownArrowRect.contains(pos))
|| (canScrollUp() && _scrollUpArrowRect.contains(pos))) {
_cursor->setCursorType(Cursor::kActive);
_cursor->setItemActive(false);
} else {
_cursor->setCursorType(Cursor::kDefault);
}
_cursor->setItemActive(false);
} else {
VisualImageXMG *cursorImage = StarkGameInterface->getCursorImage(_selectedInventoryItem);
_cursor->setCursorImage(cursorImage);
_cursor->setItemActive(hoveredItemAction == _selectedInventoryItem);
}
if (hoveredItem) {
Common::String hint = StarkGameInterface->getItemTitle(hoveredItem);
_cursor->setMouseHint(hint);
} else {
_cursor->setMouseHint("");
}
if (!_backgroundRect.contains(pos)) {
if (_autoCloseTimeRemaining == kAutoCloseSuspended) {
_autoCloseTimeRemaining = kAutoCloseDelay;
}
} else {
_autoCloseTimeRemaining = kAutoCloseSuspended;
}
}
void InventoryWindow::onClick(const Common::Point &pos) {
_actionMenu->close();
Resources::ItemVisual *clickedItem = nullptr;
int16 clickedItemAction = -1;
checkObjectAtPos(pos, &clickedItem, _selectedInventoryItem, clickedItemAction);
if (clickedItem) {
// An item was clicked
if (clickedItemAction != -1) {
// A single action is possible
if (clickedItemAction == Resources::PATTable::kActionUse) {
setSelectedInventoryItem(clickedItem->getIndex());
} else {
StarkGameInterface->itemDoAction(clickedItem, clickedItemAction);
}
} else {
// Multiple actions are possible
if (_selectedInventoryItem == -1) {
_actionMenu->open(clickedItem, Common::Point());
}
}
} else if (_scrollDownArrowRect.contains(pos)) {
if (canScrollDown()) {
scrollDown();
}
} else if (_scrollUpArrowRect.contains(pos)) {
if (canScrollUp()) {
scrollUp();
}
} else {
// Nothing was under the mouse cursor, close the inventory
close();
}
}
void InventoryWindow::onRightClick(const Common::Point &pos) {
if (_selectedInventoryItem == -1) {
close();
} else {
setSelectedInventoryItem(-1);
}
}
void InventoryWindow::reset() {
_renderEntries.clear();
}
bool InventoryWindow::isSlotVisible(uint32 slot) const {
return slot < _firstVisibleSlot + _visibleSlotsCount;
}
bool InventoryWindow::canScrollDown() const {
return _renderEntries.size() - _firstVisibleSlot > _visibleSlotsCount;
}
bool InventoryWindow::canScrollUp() const {
return _firstVisibleSlot > 0;
}
void InventoryWindow::scrollDown() {
if (canScrollDown()) {
_firstVisibleSlot += _visibleSlotsCount;
}
}
void InventoryWindow::scrollUp() {
if (canScrollUp()) {
_firstVisibleSlot -= _visibleSlotsCount;
}
}
void InventoryWindow::onGameLoop() {
if (_autoCloseTimeRemaining >= 0 && !_actionMenu->isVisible()) {
_autoCloseTimeRemaining -= StarkGlobal->getMillisecondsPerGameloop();
if (_autoCloseTimeRemaining <= 0) {
_autoCloseTimeRemaining = kAutoCloseSuspended;
close();
}
}
}
} // End of namespace Stark

View File

@@ -0,0 +1,95 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef STARK_UI_INVENTORY_WINDOW_H
#define STARK_UI_INVENTORY_WINDOW_H
#include "engines/stark/gfx/renderentry.h"
#include "engines/stark/ui/window.h"
#include "common/scummsys.h"
#include "common/rect.h"
#include "common/array.h"
namespace Stark {
class ActionMenu;
namespace Resources {
class Anim;
}
class InventoryWindow : public Window {
public:
InventoryWindow(Gfx::Driver *gfx, Cursor *cursor, ActionMenu *actionMenu);
~InventoryWindow() override {}
void open();
void close();
void setSelectedInventoryItem(int16 selectedInventoryItem);
int16 getSelectedInventoryItem() const;
/** Clear the location dependent state */
void reset();
/** Scroll the inventory */
void scrollDown();
void scrollUp();
protected:
void onMouseMove(const Common::Point &pos) override;
void onClick(const Common::Point &pos) override;
void onRightClick(const Common::Point &pos) override;
void onGameLoop() override;
void onRender() override;
void checkObjectAtPos(Common::Point pos, Resources::ItemVisual **item, int16 selectedInventoryItem, int16 &singlePossibleAction);
Common::Rect getSlotRect(uint32 slot) const;
Common::Rect getItemRect(uint32 slot, VisualImageXMG *image) const;
bool isSlotVisible(uint32 slot) const;
bool canScrollUp() const;
bool canScrollDown() const;
void drawScrollArrows() const;
private:
ActionMenu *_actionMenu;
VisualImageXMG *_backgroundImage;
Common::Rect _backgroundRect;
VisualImageXMG *_scrollUpArrowImage;
VisualImageXMG *_scrollDownArrowImage;
Common::Rect _scrollUpArrowRect;
Common::Rect _scrollDownArrowRect;
uint32 _firstVisibleSlot;
static const uint32 _visibleSlotsCount = 15;
Gfx::RenderEntryArray _renderEntries;
int16 _selectedInventoryItem;
int32 _autoCloseTimeRemaining;
};
} // End of namespace Stark
#endif // STARK_UI_INVENTORY_WINDOW_H

View File

@@ -0,0 +1,191 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#include "engines/stark/ui/world/topmenu.h"
#include "engines/stark/ui/cursor.h"
#include "engines/stark/ui/world/button.h"
#include "engines/stark/gfx/driver.h"
#include "engines/stark/resources/knowledgeset.h"
#include "engines/stark/resources/sound.h"
#include "engines/stark/services/diary.h"
#include "engines/stark/services/global.h"
#include "engines/stark/services/services.h"
#include "engines/stark/services/userinterface.h"
#include "engines/stark/services/gamemessage.h"
#include "engines/stark/visual/image.h"
namespace Stark {
TopMenu::TopMenu(Gfx::Driver *gfx, Cursor *cursor) :
Window(gfx, cursor),
_widgetsVisible(false),
_newInventoryItemExplosionAnimTimeRemaining(0),
_newDiaryEntryAnimTimeRemaining(0),
_newInventoryItemChestClosingAnimTimeRemaining(0) {
_position = Common::Rect(Gfx::Driver::kOriginalWidth, Gfx::Driver::kTopBorderHeight);
_visible = true;
Common::String inventoryText = StarkGameMessage->getTextByKey(GameMessage::kInventory);
Common::String optionsText = StarkGameMessage->getTextByKey(GameMessage::kOptions);
Common::String quitText = StarkGameMessage->getTextByKey(GameMessage::kQuit);
_inventoryButton = new Button(inventoryText, StaticProvider::kInventory, Common::Point(32, 2), Button::kAlignLeft, Common::Point(64, 20));
_optionsButton = new Button(optionsText, StaticProvider::kDiaryNormal, Common::Point(560, 2), Button::kAlignRight, Common::Point(560, 20));
_exitButton = new Button(quitText, StaticProvider::kQuit, Common::Point(608, 2), Button::kAlignRight, Common::Point(608, 20));
_inventoryNewItemSound = StarkStaticProvider->getUISound(StaticProvider::kInventoryNewItem);
}
TopMenu::~TopMenu() {
delete _exitButton;
delete _inventoryButton;
delete _optionsButton;
}
void TopMenu::onGameLoop() {
_widgetsVisible = (isMouseInside() && StarkUserInterface->isInteractive()) || isAnimationPlaying();
if (!_widgetsVisible) {
return;
}
if (StarkDiary->hasUnreadEntries()) {
_optionsButton->setUIElement(StaticProvider::kDiaryTabbed);
} else {
_optionsButton->setUIElement(StaticProvider::kDiaryNormal);
}
updateAnimations();
}
void TopMenu::onRender() {
if (!_widgetsVisible) {
return;
}
_inventoryButton->render();
_optionsButton->render();
_exitButton->render();
}
bool TopMenu::isAnimationPlaying() const {
return _newInventoryItemExplosionAnimTimeRemaining > 0
|| _newDiaryEntryAnimTimeRemaining > 0
|| _newInventoryItemChestClosingAnimTimeRemaining > 0;
}
void TopMenu::updateAnimations() {
if (_newInventoryItemExplosionAnimTimeRemaining > 0) {
_newInventoryItemExplosionAnimTimeRemaining -= StarkGlobal->getMillisecondsPerGameloop();
if (_newInventoryItemExplosionAnimTimeRemaining <= 0) {
_inventoryButton->stopImageExplosion();
_newInventoryItemChestClosingAnimTimeRemaining = 20 * 33; // 20 frames at 30 fps
_inventoryButton->goToAnimStatement(12);
}
}
if (_newInventoryItemChestClosingAnimTimeRemaining > 0) {
_newInventoryItemChestClosingAnimTimeRemaining -= StarkGlobal->getMillisecondsPerGameloop();
}
if (_newDiaryEntryAnimTimeRemaining > 0) {
_newDiaryEntryAnimTimeRemaining -= StarkGlobal->getMillisecondsPerGameloop();
if (_newDiaryEntryAnimTimeRemaining <= 0) {
_optionsButton->stopImageFlashing();
}
}
}
void TopMenu::onMouseMove(const Common::Point &pos) {
if (_widgetsVisible && StarkUserInterface->isInteractive()) {
Button *hoveredButton = getButtonAtPosition(pos);
if (hoveredButton) {
_cursor->setCursorType(Cursor::kActive);
hoveredButton->showButtonHint();
} else {
_cursor->setCursorType(Cursor::kDefault);
}
} else {
_cursor->setCursorType(Cursor::kPassive);
}
}
void TopMenu::onClick(const Common::Point &pos) {
if (!_widgetsVisible || !StarkUserInterface->isInteractive()) {
return;
}
if (_exitButton->containsPoint(pos)) {
StarkUserInterface->confirm(GameMessage::kQuitGamePrompt, StarkUserInterface,
&UserInterface::requestQuitToMainMenu);
}
if (_inventoryButton->containsPoint(pos)) {
StarkUserInterface->inventoryOpen(true);
}
if (_optionsButton->containsPoint(pos)) {
StarkUserInterface->optionsOpen();
}
}
Button *TopMenu::getButtonAtPosition(const Common::Point &point) const {
if (_exitButton->containsPoint(point)) {
return _exitButton;
} else if (_optionsButton->containsPoint(point)) {
return _optionsButton;
} else if (_inventoryButton->containsPoint(point)) {
return _inventoryButton;
}
return nullptr;
}
void TopMenu::onScreenChanged() {
_exitButton->resetHintVisual();
_inventoryButton->resetHintVisual();
_optionsButton->resetHintVisual();
}
void TopMenu::notifyInventoryItemEnabled(uint16 itemIndex) {
_newInventoryItemExplosionAnimTimeRemaining = 128 * 33; // 128 frames at 30 fps
_inventoryButton->goToAnimStatement(2);
Visual *inventoryItemImage = StarkGlobal->getInventory()->getInventoryItemVisual(itemIndex);
_inventoryButton->startImageExplosion(inventoryItemImage->get<VisualImageXMG>());
assert(_inventoryNewItemSound);
_inventoryNewItemSound->stop();
_inventoryNewItemSound->play();
}
void TopMenu::notifyDiaryEntryEnabled() {
if (StarkDiary->isEnabled()) {
_newDiaryEntryAnimTimeRemaining = 5000;
VisualImageXMG *diaryImage = StarkStaticProvider->getUIElement(StaticProvider::kDiaryTabbed);
_optionsButton->startImageFlashing(diaryImage);
}
}
} // End of namespace Stark

View File

@@ -0,0 +1,77 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef STARK_UI_TOPMENU_H
#define STARK_UI_TOPMENU_H
#include "common/scummsys.h"
#include "common/rect.h"
#include "engines/stark/ui/window.h"
namespace Stark {
class VisualImageXMG;
class Button;
namespace Resources {
class Sound;
}
class TopMenu : public Window {
public:
TopMenu(Gfx::Driver *gfx, Cursor *cursor);
~TopMenu() override;
// Window API
void onGameLoop() override;
void onRender() override;
void onMouseMove(const Common::Point &pos) override;
void onClick(const Common::Point &pos) override;
/** The screen resolution changed, rebuild the text accordingly */
void onScreenChanged();
/** A new item has been added to the player's inventory. Play relevant animation */
void notifyInventoryItemEnabled(uint16 itemIndex);
/** A new entry has been added to the player's diary. Play relevant animation */
void notifyDiaryEntryEnabled();
private:
Button *getButtonAtPosition(const Common::Point &point) const;
bool isAnimationPlaying() const;
void updateAnimations();
bool _widgetsVisible;
Button *_inventoryButton;
Button *_exitButton;
Button *_optionsButton;
int _newInventoryItemExplosionAnimTimeRemaining;
int _newInventoryItemChestClosingAnimTimeRemaining;
int _newDiaryEntryAnimTimeRemaining;
Resources::Sound *_inventoryNewItemSound;
};
} // End of namespace Stark
#endif // STARK_UI_TOPMENU_H