1 /* ResidualVM - A 3D game interpreter
2 *
3 * ResidualVM is the legal property of its developers, whose names
4 * are too numerous to list here. Please refer to the AUTHORS
5 * file distributed with this source distribution.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 *
21 */
22
23 #include "engines/stark/ui/gamewindow.h"
24
25 #include "engines/stark/scene.h"
26
27 #include "engines/stark/gfx/driver.h"
28
29 #include "engines/stark/resources/anim.h"
30 #include "engines/stark/resources/knowledgeset.h"
31 #include "engines/stark/resources/item.h"
32 #include "engines/stark/resources/location.h"
33
34 #include "engines/stark/services/global.h"
35 #include "engines/stark/services/services.h"
36 #include "engines/stark/services/staticprovider.h"
37 #include "engines/stark/services/gameinterface.h"
38 #include "engines/stark/services/userinterface.h"
39
40 #include "engines/stark/ui/actionmenu.h"
41 #include "engines/stark/ui/cursor.h"
42 #include "engines/stark/ui/inventorywindow.h"
43
44 namespace Stark {
45
GameWindow(Gfx::Driver * gfx,Cursor * cursor,ActionMenu * actionMenu,InventoryWindow * inventory)46 GameWindow::GameWindow(Gfx::Driver *gfx, Cursor *cursor, ActionMenu *actionMenu, InventoryWindow *inventory) :
47 Window(gfx, cursor),
48 _actionMenu(actionMenu),
49 _inventory(inventory),
50 _objectUnderCursor(nullptr) {
51 _position = Common::Rect(Gfx::Driver::kGameViewportWidth, Gfx::Driver::kGameViewportHeight);
52 _position.translate(0, Gfx::Driver::kTopBorderHeight);
53 _visible = true;
54
55 _fadeRenderer = _gfx->createFadeRenderer();
56 }
57
~GameWindow()58 GameWindow::~GameWindow() {
59 delete _fadeRenderer;
60 }
61
onRender()62 void GameWindow::onRender() {
63 // List the items to render
64 Resources::Location *location = StarkGlobal->getCurrent()->getLocation();
65 _renderEntries = location->listRenderEntries();
66 Gfx::LightEntryArray lightEntries = location->listLightEntries();
67
68 // Render all the scene items
69 Gfx::RenderEntryArray::iterator element = _renderEntries.begin();
70 while (element != _renderEntries.end()) {
71 // Draw the current element
72 (*element)->render(lightEntries);
73
74 // Go for the next one
75 element++;
76 }
77
78 float fadeLevel = StarkScene->getFadeLevel();
79 if ((1.0f - fadeLevel) > 0.00001f) {
80 _fadeRenderer->render(fadeLevel);
81 }
82 }
83
onMouseMove(const Common::Point & pos)84 void GameWindow::onMouseMove(const Common::Point &pos) {
85 _renderEntries = StarkGlobal->getCurrent()->getLocation()->listRenderEntries();
86 _cursor->setFading(false);
87
88 if (!StarkUserInterface->isInteractive()) {
89 _objectUnderCursor = nullptr;
90 _cursor->setCursorType(Cursor::kPassive);
91 _cursor->setMouseHint("");
92 return;
93 }
94
95 int16 selectedInventoryItem = _inventory->getSelectedInventoryItem();
96 int16 singlePossibleAction = -1;
97 bool defaultAction = false;
98
99 checkObjectAtPos(pos, selectedInventoryItem, singlePossibleAction, defaultAction);
100
101 Common::String mouseHint;
102
103 if (selectedInventoryItem != -1 && !defaultAction) {
104 VisualImageXMG *cursorImage = StarkGameInterface->getCursorImage(selectedInventoryItem);
105 _cursor->setCursorImage(cursorImage);
106 _cursor->setFading(singlePossibleAction == selectedInventoryItem);
107 } else if (_objectUnderCursor) {
108 switch (singlePossibleAction) {
109 case -1:
110 _cursor->setCursorType(Cursor::kActive);
111 break;
112 case Resources::PATTable::kActionLook:
113 _cursor->setCursorType(Cursor::kEye);
114 break;
115 case Resources::PATTable::kActionTalk:
116 _cursor->setCursorType(Cursor::kMouth);
117 break;
118 case Resources::PATTable::kActionUse:
119 _cursor->setCursorType(Cursor::kHand);
120 break;
121 default:
122 VisualImageXMG *cursorImage = StarkGameInterface->getCursorImage(singlePossibleAction);
123 _cursor->setCursorImage(cursorImage);
124 break;
125 }
126
127 mouseHint = StarkGameInterface->getItemTitleAt(_objectUnderCursor, _objectRelativePosition);
128 } else {
129 // Not an object
130 _cursor->setCursorType(Cursor::kDefault);
131 }
132 _cursor->setMouseHint(mouseHint);
133 }
134
onClick(const Common::Point & pos)135 void GameWindow::onClick(const Common::Point &pos) {
136 if (!StarkUserInterface->isInteractive()) {
137 StarkUserInterface->markInteractionDenied();
138 return;
139 }
140
141 _actionMenu->close();
142
143 int16 selectedInventoryItem = _inventory->getSelectedInventoryItem();
144 int16 singlePossibleAction = -1;
145 bool defaultAction;
146
147 checkObjectAtPos(pos, selectedInventoryItem, singlePossibleAction, defaultAction);
148
149 if (_objectUnderCursor) {
150 if (singlePossibleAction != -1) {
151 StarkGameInterface->itemDoActionAt(_objectUnderCursor, singlePossibleAction, _objectRelativePosition);
152 } else if (selectedInventoryItem == -1) {
153 _actionMenu->open(_objectUnderCursor, _objectRelativePosition);
154 }
155 } else {
156 // The walk code expects unscaled absolute mouse coordinates
157 StarkGameInterface->walkTo(_cursor->getMousePosition(true));
158 }
159 }
160
onRightClick(const Common::Point & pos)161 void GameWindow::onRightClick(const Common::Point &pos) {
162 if (!StarkUserInterface->isInteractive()) {
163 return;
164 }
165
166 int16 selectedInventoryItem = _inventory->getSelectedInventoryItem();
167
168 if (selectedInventoryItem == -1) {
169 _inventory->open();
170 } else {
171 _inventory->setSelectedInventoryItem(-1);
172 }
173 }
174
onDoubleClick(const Common::Point & pos)175 void GameWindow::onDoubleClick(const Common::Point &pos) {
176 if (!StarkUserInterface->isInteractive()) {
177 StarkUserInterface->markInteractionDenied();
178 return;
179 }
180
181 if (StarkGameInterface->isAprilWalking()) {
182 StarkGameInterface->setAprilRunning();
183 }
184 }
185
checkObjectAtPos(Common::Point pos,int16 selectedInventoryItem,int16 & singlePossibleAction,bool & isDefaultAction)186 void GameWindow::checkObjectAtPos(Common::Point pos, int16 selectedInventoryItem, int16 &singlePossibleAction, bool &isDefaultAction) {
187 _objectUnderCursor = nullptr;
188 singlePossibleAction = -1;
189 isDefaultAction = false;
190
191 Math::Ray ray = StarkScene->makeRayFromMouse(_cursor->getMousePosition(true));
192
193 // Render entries are sorted from the farthest to the camera to the nearest
194 // Loop in reverse order
195 for (int i = _renderEntries.size() - 1; i >= 0; i--) {
196 if (_renderEntries[i]->containsPoint(pos, _objectRelativePosition)
197 || _renderEntries[i]->intersectRay(ray)) {
198 _objectUnderCursor = _renderEntries[i]->getOwner();
199 break;
200 }
201 }
202
203 if (!_objectUnderCursor || !StarkGameInterface->itemHasActionAt(_objectUnderCursor, _objectRelativePosition, -1)) {
204 // Only consider items with runnable scripts
205 _objectUnderCursor = nullptr;
206 return;
207 }
208
209 int32 defaultAction = StarkGameInterface->itemGetDefaultActionAt(_objectUnderCursor, _objectRelativePosition);
210 if (defaultAction != -1) {
211 // Use the default action if there is one
212 singlePossibleAction = defaultAction;
213 isDefaultAction = true;
214 } else if (selectedInventoryItem != -1) {
215 // Use the selected inventory item if there is one
216 if (StarkGameInterface->itemHasActionAt(_objectUnderCursor, _objectRelativePosition, selectedInventoryItem)) {
217 singlePossibleAction = selectedInventoryItem;
218 }
219 } else {
220 // Otherwise, use stock actions
221 Resources::ActionArray actionsPossible = StarkGameInterface->listStockActionsPossibleForObjectAt(
222 _objectUnderCursor, _objectRelativePosition);
223
224 if (actionsPossible.size() == 1) {
225 singlePossibleAction = actionsPossible[0];
226 }
227 }
228 }
229
reset()230 void GameWindow::reset() {
231 _renderEntries.clear();
232 _objectUnderCursor = nullptr;
233 _objectRelativePosition.x = 0;
234 _objectRelativePosition.y = 0;
235 }
236
237 } // End of namespace Stark
238