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 "common/endian.h"
27 #include "engines/util.h"
28 #include "access/access.h"
29 #include "access/events.h"
30 #include "access/player.h"
31 #include "access/amazon/amazon_resources.h"
32 
33 #define CURSOR_WIDTH 16
34 #define CURSOR_HEIGHT 16
35 
36 namespace Access {
37 
EventsManager(AccessEngine * vm)38 EventsManager::EventsManager(AccessEngine *vm) : _vm(vm) {
39 	_cursorId = CURSOR_NONE;
40 	_normalMouse = CURSOR_CROSSHAIRS;
41 	_frameCounter = 10;
42 	_priorFrameTime = 0;
43 	_leftButton = _rightButton = false;
44 	_middleButton = false;
45 	_wheelUp = _wheelDown = false;
46 	_mouseCol = _mouseRow = 0;
47 	_cursorExitFlag = false;
48 	_vbCount = 0;
49 	_keyCode = Common::KEYCODE_INVALID;
50 	_priorTimerTime = 0;
51 }
52 
~EventsManager()53 EventsManager::~EventsManager() {
54 	_invCursor.free();
55 }
56 
forceSetCursor(CursorType cursorId)57 void EventsManager::forceSetCursor(CursorType cursorId) {
58 	setNormalCursor(cursorId);
59 	setCursor(cursorId);
60 }
61 
setNormalCursor(CursorType cursorId)62 void EventsManager::setNormalCursor(CursorType cursorId) {
63 	_normalMouse = cursorId;
64 }
65 
setCursor(CursorType cursorId)66 void EventsManager::setCursor(CursorType cursorId) {
67 	if (cursorId == _cursorId)
68 		return;
69 	_cursorId = cursorId;
70 
71 	if (cursorId == CURSOR_INVENTORY) {
72 		// Set the cursor
73 		CursorMan.replaceCursor(_invCursor.getPixels(), _invCursor.w, _invCursor.h,
74 			_invCursor.w / 2, _invCursor.h / 2, 0);
75 	} else {
76 		// Get a pointer to the mouse data to use, and get the cursor hotspot
77 		const byte *srcP = &_vm->_res->CURSORS[cursorId][0];
78 		int hotspotX = (int16)READ_LE_UINT16(srcP);
79 		int hotspotY = (int16)READ_LE_UINT16(srcP + 2);
80 		srcP += 4;
81 
82 		// Create a surface to build up the cursor on
83 		Graphics::Surface cursorSurface;
84 		cursorSurface.create(CURSOR_WIDTH, CURSOR_HEIGHT, Graphics::PixelFormat::createFormatCLUT8());
85 		byte *destP = (byte *)cursorSurface.getPixels();
86 		Common::fill(destP, destP + CURSOR_WIDTH * CURSOR_HEIGHT, 0);
87 
88 		// Loop to build up the cursor
89 		for (int y = 0; y < CURSOR_HEIGHT; ++y) {
90 			destP = (byte *)cursorSurface.getBasePtr(0, y);
91 			int width = CURSOR_WIDTH;
92 			int skip = *srcP++;
93 			int plot = *srcP++;
94 			if (skip >= width)
95 				break;
96 
97 			// Skip over pixels
98 			destP += skip;
99 			width -= skip;
100 
101 			// Write out the pixels to plot
102 			while (plot > 0 && width > 0) {
103 				*destP++ = *srcP++;
104 				--plot;
105 				--width;
106 			}
107 		}
108 
109 		// Set the cursor
110 		CursorMan.replaceCursor(cursorSurface.getPixels(), CURSOR_WIDTH, CURSOR_HEIGHT,
111 			hotspotX, hotspotY, 0);
112 
113 		// Free the cursor surface
114 		cursorSurface.free();
115 	}
116 }
117 
setCursorData(Graphics::ManagedSurface * src,const Common::Rect & r)118 void EventsManager::setCursorData(Graphics::ManagedSurface *src, const Common::Rect &r) {
119 	_invCursor.create(r.width(), r.height(), Graphics::PixelFormat::createFormatCLUT8());
120 	_invCursor.copyRectToSurface(*src, 0, 0, r);
121 }
122 
showCursor()123 void EventsManager::showCursor() {
124 	CursorMan.showMouse(true);
125 }
126 
hideCursor()127 void EventsManager::hideCursor() {
128 	CursorMan.showMouse(false);
129 }
130 
isCursorVisible()131 bool EventsManager::isCursorVisible() {
132 	return CursorMan.isVisible();
133 }
134 
pollEvents(bool skipTimers)135 void EventsManager::pollEvents(bool skipTimers) {
136 	if (checkForNextFrameCounter()) {
137 		nextFrame();
138 	}
139 
140 	if (checkForNextTimerUpdate() && !skipTimers)
141 		nextTimer();
142 
143 	_vm->_sound->checkSoundQueue();
144 
145 	_wheelUp = _wheelDown = false;
146 
147 	Common::Event event;
148 	while (g_system->getEventManager()->pollEvent(event)) {
149 		switch (event.type) {
150 		case Common::EVENT_QUIT:
151 		case Common::EVENT_RETURN_TO_LAUNCHER:
152 			return;
153 
154 		case Common::EVENT_KEYDOWN:
155 			// Check for debugger
156 			keyControl(event.kbd.keycode, true);
157 			return;
158 		case Common::EVENT_KEYUP:
159 			keyControl(event.kbd.keycode, false);
160 			return;
161 		case Common::EVENT_MOUSEMOVE:
162 			_mousePos = event.mouse;
163 			_mouseCol = _mousePos.x / 8;
164 			_mouseRow = _mousePos.y / 8;
165 			break;
166 		case Common::EVENT_LBUTTONDOWN:
167 			_leftButton = true;
168 			return;
169 		case Common::EVENT_LBUTTONUP:
170 			_leftButton = false;
171 			return;
172 		case Common::EVENT_RBUTTONDOWN:
173 			_rightButton = true;
174 			return;
175 		case Common::EVENT_RBUTTONUP:
176 			_rightButton = false;
177 			return;
178 		case Common::EVENT_MBUTTONDOWN:
179 			_middleButton = true;
180 			return;
181 		case Common::EVENT_MBUTTONUP:
182 			_middleButton = false;
183 			return;
184 		case Common::EVENT_WHEELUP:
185 			_wheelUp = true;
186 			return;
187 		case Common::EVENT_WHEELDOWN:
188 			_wheelDown = true;
189 			return;
190 		default:
191  			break;
192 		}
193 	}
194 }
195 
keyControl(Common::KeyCode keycode,bool isKeyDown)196 void EventsManager::keyControl(Common::KeyCode keycode, bool isKeyDown) {
197 	Player &player = *_vm->_player;
198 
199 	if (!isKeyDown) {
200 		if (player._move != NONE) {
201 			_keyCode = Common::KEYCODE_INVALID;
202 			player._move = NONE;
203 		}
204 		return;
205 	}
206 
207 	_keyCode = keycode;
208 
209 	switch (keycode) {
210 	case Common::KEYCODE_UP:
211 	case Common::KEYCODE_KP8:
212 		player._move = UP;
213 		break;
214 	case Common::KEYCODE_DOWN:
215 	case Common::KEYCODE_KP2:
216 		player._move = DOWN;
217 		break;
218 	case Common::KEYCODE_LEFT:
219 	case Common::KEYCODE_KP4:
220 		player._move = LEFT;
221 		break;
222 	case Common::KEYCODE_RIGHT:
223 	case Common::KEYCODE_KP6:
224 		player._move = RIGHT;
225 		break;
226 	case Common::KEYCODE_KP7:
227 		player._move = UPLEFT;
228 		break;
229 	case Common::KEYCODE_KP9:
230 		player._move = UPRIGHT;
231 		break;
232 	case Common::KEYCODE_KP1:
233 		player._move = DOWNLEFT;
234 		break;
235 	case Common::KEYCODE_KP3:
236 		player._move = DOWNRIGHT;
237 		break;
238 	default:
239 		break;
240 	}
241 }
242 
pollEventsAndWait()243 void EventsManager::pollEventsAndWait() {
244 	pollEvents();
245 	delay();
246 }
247 
checkForNextFrameCounter()248 bool EventsManager::checkForNextFrameCounter() {
249 	// Check for next game frame
250 	uint32 milli = g_system->getMillis();
251 	if ((milli - _priorFrameTime) >= GAME_FRAME_TIME) {
252 		--_vbCount;
253 		++_frameCounter;
254 		_priorFrameTime = milli;
255 
256 		return true;
257 	}
258 
259 	return false;
260 }
261 
checkForNextTimerUpdate()262 bool EventsManager::checkForNextTimerUpdate() {
263 	// Check for next timer update
264 	uint32 milli = g_system->getMillis();
265 	if ((milli - _priorTimerTime) >= GAME_TIMER_TIME) {
266 		_priorTimerTime = milli;
267 
268 		return true;
269 	}
270 
271 	return false;
272 }
273 
nextFrame()274 void EventsManager::nextFrame() {
275 	_vm->_screen->update();
276 }
277 
nextTimer()278 void EventsManager::nextTimer() {
279 	_vm->_animation->updateTimers();
280 	_vm->_timers.updateTimers();
281 }
282 
delay(int time)283 void EventsManager::delay(int time) {
284 	g_system->delayMillis(time);
285 }
286 
zeroKeys()287 void EventsManager::zeroKeys() {
288 	_keyCode = Common::KEYCODE_INVALID;
289 }
290 
getKey(Common::KeyState & key)291 bool EventsManager::getKey(Common::KeyState &key) {
292 	if (_keyCode == Common::KEYCODE_INVALID) {
293 		return false;
294 	} else {
295 		key = _keyCode;
296 		_keyCode = Common::KEYCODE_INVALID;
297 		return true;
298 	}
299 }
300 
isKeyPending() const301 bool EventsManager::isKeyPending() const {
302 	return _keyCode != Common::KEYCODE_INVALID;
303 }
304 
debounceLeft()305 void EventsManager::debounceLeft() {
306 	while (_leftButton && !_vm->shouldQuit()) {
307 		pollEventsAndWait();
308 	}
309 }
310 
clearEvents()311 void EventsManager::clearEvents() {
312 	_leftButton = _rightButton = false;
313 	zeroKeys();
314 }
315 
waitKeyMouse()316 void EventsManager::waitKeyMouse() {
317 	while (!_vm->shouldQuit() && !isKeyMousePressed()) {
318 		pollEvents(true);
319 		delay();
320 	}
321 }
322 
calcRawMouse()323 Common::Point EventsManager::calcRawMouse() {
324 	Common::Point pt;
325 	Screen &screen = *_vm->_screen;
326 	pt.x = _mousePos.x - screen._windowXAdd +
327 		(_vm->_scrollCol * TILE_WIDTH) + _vm->_scrollX;
328 	pt.y = _mousePos.y - screen._screenYOff - screen._windowYAdd +
329 		(_vm->_scrollRow * TILE_HEIGHT) + _vm->_scrollY;
330 
331 	return pt;
332 }
333 
checkMouseBox1(Common::Array<Common::Rect> & rects)334 int EventsManager::checkMouseBox1(Common::Array<Common::Rect> &rects) {
335 	for (uint16 i = 0; i < rects.size(); ++i) {
336 		if (rects[i].left == -1)
337 			return -1;
338 
339 		if ((_mousePos.x > rects[i].left) && (_mousePos.x < rects[i].right)
340 			&& (_mousePos.y > rects[i].top) && (_mousePos.y < rects[i].bottom))
341 			return i;
342 	}
343 
344 	return -1;
345 }
346 
isKeyMousePressed()347 bool EventsManager::isKeyMousePressed() {
348 	bool result = _leftButton || _rightButton || isKeyPending();
349 	debounceLeft();
350 	zeroKeys();
351 
352 	return result;
353 }
354 
centerMousePos()355 void EventsManager::centerMousePos() {
356 	_mousePos = Common::Point(160, 100);
357 }
358 
restrictMouse()359 void EventsManager::restrictMouse() {
360 	// No implementation in ScummVM
361 }
362 
363 } // End of namespace Access
364