Initial commit
This commit is contained in:
250
engines/stark/ui/world/actionmenu.cpp
Normal file
250
engines/stark/ui/world/actionmenu.cpp
Normal 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
|
||||
99
engines/stark/ui/world/actionmenu.h
Normal file
99
engines/stark/ui/world/actionmenu.h
Normal 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
|
||||
129
engines/stark/ui/world/button.cpp
Normal file
129
engines/stark/ui/world/button.cpp
Normal 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
|
||||
89
engines/stark/ui/world/button.h
Normal file
89
engines/stark/ui/world/button.h
Normal 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
|
||||
63
engines/stark/ui/world/clicktext.cpp
Normal file
63
engines/stark/ui/world/clicktext.cpp
Normal 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
|
||||
60
engines/stark/ui/world/clicktext.h
Normal file
60
engines/stark/ui/world/clicktext.h
Normal 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
|
||||
382
engines/stark/ui/world/dialogpanel.cpp
Normal file
382
engines/stark/ui/world/dialogpanel.cpp
Normal 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
|
||||
116
engines/stark/ui/world/dialogpanel.h
Normal file
116
engines/stark/ui/world/dialogpanel.h
Normal 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
|
||||
116
engines/stark/ui/world/fmvscreen.cpp
Normal file
116
engines/stark/ui/world/fmvscreen.cpp
Normal 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
|
||||
67
engines/stark/ui/world/fmvscreen.h
Normal file
67
engines/stark/ui/world/fmvscreen.h
Normal 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
|
||||
157
engines/stark/ui/world/gamescreen.cpp
Normal file
157
engines/stark/ui/world/gamescreen.cpp
Normal 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
|
||||
94
engines/stark/ui/world/gamescreen.h
Normal file
94
engines/stark/ui/world/gamescreen.h
Normal 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
|
||||
290
engines/stark/ui/world/gamewindow.cpp
Normal file
290
engines/stark/ui/world/gamewindow.cpp
Normal 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
|
||||
78
engines/stark/ui/world/gamewindow.h
Normal file
78
engines/stark/ui/world/gamewindow.h
Normal 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
|
||||
302
engines/stark/ui/world/inventorywindow.cpp
Normal file
302
engines/stark/ui/world/inventorywindow.cpp
Normal 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
|
||||
95
engines/stark/ui/world/inventorywindow.h
Normal file
95
engines/stark/ui/world/inventorywindow.h
Normal 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
|
||||
191
engines/stark/ui/world/topmenu.cpp
Normal file
191
engines/stark/ui/world/topmenu.cpp
Normal 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
|
||||
77
engines/stark/ui/world/topmenu.h
Normal file
77
engines/stark/ui/world/topmenu.h
Normal 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
|
||||
Reference in New Issue
Block a user