1 /* ScummVM - Graphic Adventure Engine
2 *
3 * ScummVM is the legal property of its developers, whose names
4 * are too numerous to list here. Please refer to the COPYRIGHT
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 "common/scummsys.h"
24 #include "graphics/cursorman.h"
25 #include "common/events.h"
26 #include "engines/util.h"
27 #include "mads/mads.h"
28 #include "mads/events.h"
29 #include "mads/scene.h"
30
31 namespace MADS {
32
EventsManager(MADSEngine * vm)33 EventsManager::EventsManager(MADSEngine *vm) {
34 _vm = vm;
35 _cursorSprites = nullptr;
36 _cursorId = CURSOR_NONE;
37 _newCursorId = CURSOR_NONE;
38 _frameCounter = 10;
39 _priorFrameTime = 0;
40 _mouseClicked = false;
41 _mouseReleased = false;
42 _mouseButtons = 0;
43 _mouseStatus = 0;
44 _strokeGoing = 0;
45 _mouseStatusCopy = 0;
46 _mouseMoved = false;
47 _rightMousePressed = false;
48 _eventTarget = nullptr;
49 }
50
~EventsManager()51 EventsManager::~EventsManager() {
52 freeCursors();
53 }
54
loadCursors(const Common::String & spritesName)55 void EventsManager::loadCursors(const Common::String &spritesName) {
56 delete _cursorSprites;
57 _cursorSprites = new SpriteAsset(_vm, spritesName, 0x4000);
58 }
59
setCursor(CursorType cursorId)60 void EventsManager::setCursor(CursorType cursorId) {
61 _cursorId = cursorId;
62 changeCursor();
63 }
64
setCursor2(CursorType cursorId)65 void EventsManager::setCursor2(CursorType cursorId) {
66 _cursorId = cursorId;
67 _newCursorId = cursorId;
68 changeCursor();
69 }
70
showCursor()71 void EventsManager::showCursor() {
72 CursorMan.showMouse(true);
73 }
74
hideCursor()75 void EventsManager::hideCursor() {
76 CursorMan.showMouse(false);
77 }
78
isCursorVisible()79 bool EventsManager::isCursorVisible() {
80 return CursorMan.isVisible();
81 }
82
waitCursor()83 void EventsManager::waitCursor() {
84 CursorType cursorId = (CursorType)MIN(_cursorSprites->getCount(), (int)CURSOR_WAIT);
85 _newCursorId = cursorId;
86 if (_cursorId != _newCursorId) {
87 _cursorId = _newCursorId;
88 changeCursor();
89 }
90 }
91
changeCursor()92 void EventsManager::changeCursor() {
93 if (_cursorSprites) {
94 MSprite *cursor = _cursorSprites->getFrame(_cursorId - 1);
95 assert(cursor->w == cursor->h);
96 byte transIndex = cursor->getTransparencyIndex();
97
98 // Check for hotspot indication pixels along the right-hand and bottom
99 // row. Put together, these give the cursor's hotspot x,y
100 int hotspotX = 0, hotspotY = 0;
101 const byte *cursorData = (const byte *)cursor->getPixels();
102 for (int idx = 0; idx < cursor->w; ++idx) {
103 if (cursorData[(cursor->h - 1) * cursor->w + idx] != transIndex)
104 hotspotX = idx;
105
106 if (cursorData[(idx + 1) * cursor->w - 1] != transIndex)
107 hotspotY = idx;
108 }
109
110 // Reduce the cursor data to remove the last column from each row, since
111 // the cursor routines don't have a pitch option
112 byte *destCursor = new byte[(cursor->w - 1) * (cursor->h - 1)];
113 const byte *srcP = cursorData;
114 byte *destP = destCursor;
115
116 for (int idx = 0; idx < (cursor->h - 1); ++idx) {
117 Common::copy(srcP, srcP + cursor->w - 1, destP);
118 srcP += cursor->w;
119 destP += cursor->w - 1;
120 }
121
122 // Set the raw cursor data to use
123 CursorMan.replaceCursor(destCursor, cursor->w - 1, cursor->h - 1,
124 hotspotX, hotspotY, transIndex);
125 showCursor();
126 delete[] destCursor;
127 }
128 }
129
freeCursors()130 void EventsManager::freeCursors() {
131 delete _cursorSprites;
132 _cursorSprites = nullptr;
133 }
134
pollEvents()135 void EventsManager::pollEvents() {
136 checkForNextFrameCounter();
137 _mouseMoved = false;
138
139 Common::Event event;
140 while (g_system->getEventManager()->pollEvent(event)) {
141 // If an event target is specified, pass the event to it
142 if (_eventTarget) {
143 _eventTarget->onEvent(event);
144 continue;
145 }
146
147 // Handle keypress
148 switch (event.type) {
149 case Common::EVENT_QUIT:
150 case Common::EVENT_RTL:
151 return;
152
153 case Common::EVENT_KEYDOWN:
154 // Check for debugger
155 if (event.kbd.keycode == Common::KEYCODE_d && (event.kbd.flags & Common::KBD_CTRL)) {
156 // Attach to the debugger
157 _vm->_debugger->attach();
158 _vm->_debugger->onFrame();
159 } else {
160 _pendingKeys.push(event.kbd);
161 }
162 return;
163 case Common::EVENT_KEYUP:
164 return;
165 case Common::EVENT_WHEELUP:
166 _pendingKeys.push(Common::KeyState(Common::KEYCODE_PAGEUP));
167 return;
168 case Common::EVENT_WHEELDOWN:
169 _pendingKeys.push(Common::KeyState(Common::KEYCODE_PAGEDOWN));
170 return;
171 case Common::EVENT_LBUTTONDOWN:
172 case Common::EVENT_RBUTTONDOWN:
173 _mouseClicked = true;
174 _mouseButtons = 1;
175 _mouseMoved = true;
176 if (event.type == Common::EVENT_RBUTTONDOWN) {
177 _rightMousePressed = true;
178 _mouseStatus |= 2;
179 } else {
180 _mouseStatus |= 1;
181 }
182 return;
183 case Common::EVENT_LBUTTONUP:
184 case Common::EVENT_RBUTTONUP:
185 _mouseClicked = false;
186 _mouseReleased = true;
187 _mouseMoved = true;
188 _rightMousePressed = false;
189 if (event.type == Common::EVENT_RBUTTONUP) {
190 _mouseStatus &= ~2;
191 } else {
192 _mouseStatus &= ~1;
193 }
194 return;
195 case Common::EVENT_MOUSEMOVE:
196 _mousePos = event.mouse;
197 _currentPos = event.mouse;
198 _mouseMoved = true;
199 break;
200 default:
201 break;
202 }
203 }
204 }
205
checkForNextFrameCounter()206 bool EventsManager::checkForNextFrameCounter() {
207 // Check for next game frame
208 uint32 milli = g_system->getMillis();
209 if ((milli - _priorFrameTime) >= GAME_FRAME_TIME) {
210 ++_frameCounter;
211 _priorFrameTime = milli;
212
213 // Do any palette cycling
214 _vm->_game->_scene.animatePalette();
215
216 // Give time to the debugger
217 _vm->_debugger->onFrame();
218
219 // Display the frame
220 _vm->_screen->update();
221
222 // Signal the ScummVM debugger
223 _vm->_debugger->onFrame();
224
225 return true;
226 }
227
228 return false;
229 }
230
delay(int cycles)231 void EventsManager::delay(int cycles) {
232 uint32 totalMilli = cycles * 1000 / GAME_FRAME_RATE;
233 uint32 delayEnd = g_system->getMillis() + totalMilli;
234
235 while (!_vm->shouldQuit() && g_system->getMillis() < delayEnd) {
236 g_system->delayMillis(10);
237
238 pollEvents();
239 }
240 }
241
waitForNextFrame()242 void EventsManager::waitForNextFrame() {
243 _mouseClicked = false;
244 _mouseReleased = false;
245 _mouseButtons = 0;
246
247 bool mouseClicked = false;
248 bool mouseReleased = false;
249 int mouseButtons = 0;
250
251 uint32 frameCtr = getFrameCounter();
252 while (!_vm->shouldQuit() && frameCtr == _frameCounter) {
253 delay(1);
254
255 mouseClicked |= _mouseClicked;
256 mouseReleased |= _mouseReleased;
257 mouseButtons |= _mouseButtons;
258 }
259
260 _mouseClicked = mouseClicked;
261 _mouseReleased = mouseReleased;
262 _mouseButtons = mouseButtons;
263 _mouseMoved |= _mouseClicked || _mouseReleased;
264 }
265
initVars()266 void EventsManager::initVars() {
267 _mousePos = Common::Point(-1, -1);
268 _mouseStatusCopy = _mouseStatus;
269 _strokeGoing = 0;
270 }
271
clearEvents()272 void EventsManager::clearEvents() {
273 _pendingKeys.clear();
274 }
275
276
277 } // End of namespace MADS
278