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 #include "dragons/cursor.h"
23 #include "dragons/actor.h"
24 #include "dragons/actorresource.h"
25 #include "dragons/dragons.h"
26 #include "dragons/dragonimg.h"
27 #include "dragons/dragonini.h"
28 #include "dragons/dragonobd.h"
29 #include "dragons/inventory.h"
30 #include "dragons/scene.h"
31 #include "dragons/scriptopcodes.h"
32 #include "dragons/screen.h"
33 
34 namespace Dragons {
35 
Cursor(DragonsEngine * vm)36 Cursor::Cursor(DragonsEngine *vm): _vm(vm), _actor(0), _x(0), _y(0) {
37 	_sequenceID = 0;
38 	_data_800728b0_cursor_seqID = 0;
39 	_iniUnderCursor = 0;
40 	_performActionTargetINI = 0;
41 	_objectInHandSequenceID = 0;
42 	_cursorActivationSeqOffset = 0;
43 	_iniItemInHand = 0;
44 	_handPointerSequenceID = _vm->getCursorHandPointerSequenceID();
45 }
46 
init(ActorManager * actorManager,DragonINIResource * dragonINIResource)47 void Cursor::init(ActorManager *actorManager, DragonINIResource *dragonINIResource) {
48 	_sequenceID = 0;
49 	_actor = actorManager->loadActor(0, 0); //Load cursor
50 	_actor->_x_pos = _x = 160;
51 	_actor->_y_pos = _y = 100;
52 	_actor->_priorityLayer = 6;
53 	_actor->_flags = 0;
54 	_actor->_scale = DRAGONS_ENGINE_SPRITE_100_PERCENT_SCALE;
55 	_actor->updateSequence(_sequenceID);
56 	_actor->_flags |= (ACTOR_FLAG_40 | Dragons::ACTOR_FLAG_80 | Dragons::ACTOR_FLAG_100 |
57 					   ACTOR_FLAG_200);
58 
59 	dragonINIResource->getFlickerRecord()->actor = _actor; //TODO is this correct?
60 	dragonINIResource->getFlickerRecord()->flags |= INI_FLAG_1;
61 	_iniUnderCursor = 0;
62 	_iniItemInHand = 0;
63 	_objectInHandSequenceID = 0;
64 	_cursorActivationSeqOffset = 0;
65 	_data_800728b0_cursor_seqID = 0;
66 	_performActionTargetINI = 0;
67 }
68 
69 
update()70 void Cursor::update() {
71 	if (!_vm->isFlagSet(ENGINE_FLAG_8) || _vm->isFlagSet(Dragons::ENGINE_FLAG_100)) {
72 		return;
73 	}
74 	// TODO update cursor from inputs here.
75 
76 	// 0x800280b8
77 	if (_sequenceID == 0 && _vm->_inventory->isOpen()) {
78 		_sequenceID = 1;
79 	}
80 
81 	_actor->_x_pos = _x;
82 	_actor->_y_pos = _y;
83 
84 	// 0x80028104
85 	if (_iniUnderCursor != 0
86 			&& ((_iniUnderCursor & 0x8000 && _vm->_inventory->isOpen())
87 			||(!(_iniUnderCursor & 0x8000) && _vm->getINI(_iniUnderCursor - 1)->flags & 0x80))) {
88 		if (_actor->_sequenceID != _handPointerSequenceID) {
89 			_actor->updateSequence(_handPointerSequenceID);
90 		}
91 		return;
92 	}
93 	int32 inventorySequenceID = _vm->_inventory->getSequenceId();
94 	if ((_iniUnderCursor == 0x8001) && (inventorySequenceID == 1)) {
95 		if (_actor->_sequenceID != _handPointerSequenceID) {
96 			_actor->updateSequence(_handPointerSequenceID);
97 		}
98 		return;
99 	}
100 
101 	if (_iniUnderCursor == 0x8002 && inventorySequenceID == 4) {//goto LAB_80028204;
102 		if (_actor->_sequenceID != _handPointerSequenceID) {
103 			_actor->updateSequence(_handPointerSequenceID);
104 		}
105 		return;
106 	}
107 
108 	if (_iniUnderCursor != 0x8002 || (inventorySequenceID != 1 && inventorySequenceID != 3)) {
109 		if ((_iniUnderCursor != 0x8001) || ((inventorySequenceID != 0 && (inventorySequenceID != 3)))) {
110 			if (_sequenceID == 5) {
111 				uint16 uVar1 = (uint) _objectInHandSequenceID;
112 				if (_cursorActivationSeqOffset != 0) {
113 					uVar1 = uVar1 + 1;
114 				}
115 				if (uVar1 == (uint) _actor->_sequenceID) {
116 					return;
117 				}
118 				_actor->updateSequence((uint) _objectInHandSequenceID + (uint) (_cursorActivationSeqOffset != 0));
119 			} else {
120 				if (_sequenceID + (uint) _cursorActivationSeqOffset != (uint) _actor->_sequenceID) {
121 					_actor->updateSequence(_sequenceID + (uint) _cursorActivationSeqOffset);
122 				}
123 			}
124 			return;
125 		}
126 	}
127 
128 	if (_iniItemInHand == 0) {
129 		if (_actor->_sequenceID != _handPointerSequenceID) {
130 			_actor->updateSequence(_handPointerSequenceID);
131 		}
132 		return;
133 	} else {
134 		if ((uint)_actor->_sequenceID != (uint)_objectInHandSequenceID + 1) {
135 			_actor->updateSequence((uint)_objectInHandSequenceID + 1);
136 		}
137 	}
138 
139 	// 0x_800281c0
140 }
141 
updateVisibility()142 void Cursor::updateVisibility() {
143 	if (_vm->isFlagSet(ENGINE_FLAG_8) && !_vm->isUnkFlagSet(Dragons::ENGINE_UNK1_FLAG_10)) {
144 		_actor->_priorityLayer = 9;
145 	} else {
146 		_actor->_priorityLayer = 0;
147 	}
148 }
149 
updatePosition(int16 x,int16 y)150 void Cursor::updatePosition(int16 x, int16 y) {
151 	_x = x;
152 	_y = y;
153 }
154 
updateINIUnderCursor()155 int16 Cursor::updateINIUnderCursor() {
156 	if (_vm->isFlagSet(ENGINE_FLAG_10)) {
157 		int16 xOffset = 0;
158 		if (_vm->_inventory->getSequenceId() == 0 || _vm->_inventory->getSequenceId() == 2) {
159 			if (_vm->_inventory->getPositionIndex() == 1 || _vm->_inventory->getPositionIndex() == 3) {
160 				xOffset = 0x32;
161 			}
162 		}
163 		Common::Point inventoryPosition = _vm->_inventory->getPosition();
164 		if (_x >= inventoryPosition.x + 0xa + xOffset
165 				&& _x < inventoryPosition.x + 0x35 + xOffset
166 				&& _y >= inventoryPosition.y + 0xa
167 				&& _y < inventoryPosition.y + 0x25) {
168 			_iniUnderCursor = 0x8001;
169 			return _iniUnderCursor;
170 		}
171 
172 		if (_x >= inventoryPosition.x + 0x36
173 				&& _x < inventoryPosition.x + 0x5f
174 				&& _y >= inventoryPosition.y + 0xa
175 				&& _y < inventoryPosition.y + 0x25
176 				&& _vm->_inventory->getPositionIndex() != 0
177 				&& _vm->_inventory->getPositionIndex() != 2) {
178 			_iniUnderCursor = 0x8002;
179 			return _iniUnderCursor;
180 		}
181 	}
182 
183 	// TODO 0x80028940
184 	if (_vm->_inventory->getState() == InventoryOpen) {
185 		_iniUnderCursor = _vm->_inventory->getIniAtPosition(_x, _y);
186 		return _iniUnderCursor;
187 	}
188 
189 	return updateIniFromScene();
190 }
191 
updateIniFromScene()192 int16 Cursor::updateIniFromScene() {
193 	int16 cursorX = _x + _vm->_scene->_camera.x;
194 	int16 cursorY = _y + _vm->_scene->_camera.y;
195 	int16 cursorTileX = cursorX / 32;
196 	int16 cursorTileY = cursorY / 8;
197 	int16 data_80072890_orig = _performActionTargetINI;
198 	int16 data_800728b0_cursor_seqID_orig = _data_800728b0_cursor_seqID;
199 
200 	for (int i = 0; i <_vm->_dragonINIResource->totalRecords(); i++) {
201 		DragonINI *ini = _vm->_dragonINIResource->getRecord(i);
202 		if (ini->sceneId != _vm->_scene->getSceneId()) {
203 			// 0x80028be4
204 		} else if (!_vm->_dragonINIResource->isFlicker(ini) && !(ini->flags & 0x40)) {
205 			int16 cursorOverIni = 0;
206 			// 0x80028a10
207 			if (ini->flags & 1) {
208 				// 0x80028b18
209 				if (ini->actor->isFlagSet(ACTOR_FLAG_40) && ini->actor->isFlagSet(ACTOR_FLAG_8)) {
210 					int16 iniActorXPosition = ini->actor->_x_pos - ini->actor->_frame->xOffset;
211 					int16 iniActorYPosition = ini->actor->_y_pos - ini->actor->_frame->yOffset;
212 					if (cursorX >= iniActorXPosition && cursorX < iniActorXPosition + ini->actor->_frame->width
213 							&& cursorY >= iniActorYPosition && cursorY < iniActorYPosition + ini->actor->_frame->height) {
214 						cursorOverIni = i + 1;
215 					}
216 				}
217 			} else {
218 				// 0x80028a24
219 				if (ini->imgId != -1) {
220 					Img *img = _vm->_dragonImg->getImg((uint32)ini->imgId);
221 					if (img->field_e - 1 >= 1) { // TODO this is >= 2 in the original.
222 						if (cursorTileX >= img->x && cursorTileX < img->x + img->w && cursorTileY >= img->y && cursorTileY < img->y + img->h) {
223 							cursorOverIni = i + 1;
224 						}
225 					} else {
226 						// 0x80028ac4
227 						if (cursorX >= img->x && cursorX < img->x + img->w && cursorY >= img->y && cursorY < img->y + img->h) {
228 							cursorOverIni = i + 1;
229 						}
230 					}
231 				}
232 			}
233 			if (cursorOverIni != 0) {
234 				// 0x80028bf0
235 				// _iniUnderCursor = cursorOverIni;
236 				_performActionTargetINI = _iniUnderCursor;
237 				_data_800728b0_cursor_seqID = _sequenceID;
238 
239 				if (ini->flags & 0x800) {
240 					_performActionTargetINI = cursorOverIni;
241 					uint32 newSeqId = 1;
242 					for (int idx = 0; idx < 5; idx++) {
243 						_data_800728b0_cursor_seqID = idx;
244 						byte *obd = _vm->_dragonOBD->getFromOpt(cursorOverIni - 1); //_dragonRMS->getAfterSceneLoadedScript(sceneId);
245 						ScriptOpCall scriptOpCall(obd + 8, READ_LE_UINT32(obd));
246 
247 //						uVar17 = uVar15;
248 //						local_58 = dragon_Obd_Offset + *(int *)(uVar16 * 8 + dragon_Opt_Offset + -8) + 8;
249 //						data_800728b0 = idx;
250 //						local_54 = read_int32();
251 //						local_54 = local_54 + local_58;
252 //						uVar6 = ;
253 						if (executeScript(scriptOpCall, 0)) {
254 							newSeqId = idx;
255 							break;
256 						}
257 					}
258 
259 					_sequenceID = newSeqId;
260 					_iniUnderCursor = cursorOverIni;
261 					_performActionTargetINI = _iniUnderCursor;
262 					_data_800728b0_cursor_seqID = _sequenceID;
263 					return _iniUnderCursor;
264 				}
265 				if (_sequenceID != 0) {
266 					_iniUnderCursor = cursorOverIni;
267 					_performActionTargetINI = data_80072890_orig;
268 					_data_800728b0_cursor_seqID = data_800728b0_cursor_seqID_orig;
269 					return _iniUnderCursor;
270 				}
271 				byte *obd = _vm->_dragonOBD->getFromOpt(cursorOverIni - 1); //_dragonRMS->getAfterSceneLoadedScript(sceneId);
272 				ScriptOpCall scriptOpCall(obd + 8, READ_LE_UINT32(obd));
273 
274 //				local_48 = dragon_Obd_Offset + *(int *)(uVar16 * 8 + dragon_Opt_Offset + -8) + 8;
275 //				local_44 = read_int32();
276 //				local_44 = local_44 + local_48;
277 				if (executeScript(scriptOpCall, 0)) {
278 					_iniUnderCursor = cursorOverIni;
279 					_performActionTargetINI = data_80072890_orig;
280 					_data_800728b0_cursor_seqID = data_800728b0_cursor_seqID_orig;
281 					return _iniUnderCursor;
282 				}
283 			}
284 		}
285 	}
286 	_iniUnderCursor = 0;
287 	_performActionTargetINI = data_80072890_orig;
288 	_data_800728b0_cursor_seqID = data_800728b0_cursor_seqID_orig;
289 	return 0;
290 }
291 
executeScript(ScriptOpCall & scriptOpCall,uint16 unkFlag)292 int16 Cursor::executeScript(ScriptOpCall &scriptOpCall, uint16 unkFlag) {
293 	int16 temp = _vm->_scriptOpcodes->_scriptTargetINI;
294 	byte *codeStart = scriptOpCall._code;
295 
296 	scriptOpCall._field8 = 1;
297 	scriptOpCall._result = 0;
298 	_vm->_scriptOpcodes->_numDialogStackFramesToPop = 0;
299 	_vm->_scriptOpcodes->executeScriptLoop(scriptOpCall);
300 
301 	if (!(scriptOpCall._result & 1) && _data_800728b0_cursor_seqID == 5 && unkFlag != 0) {
302 		_vm->_scriptOpcodes->_scriptTargetINI = -1;
303 		scriptOpCall._code = codeStart;
304 		scriptOpCall._field8 = 1;
305 		scriptOpCall._result = 0;
306 		_vm->_scriptOpcodes->_numDialogStackFramesToPop = 0;
307 		_vm->_scriptOpcodes->executeScriptLoop(scriptOpCall);
308 		_vm->_scriptOpcodes->_scriptTargetINI = temp;
309 		if (scriptOpCall._result & 1) {
310 			scriptOpCall._result |= 2;
311 		}
312 	}
313 	return scriptOpCall._result & 3;
314 }
315 
selectPreviousCursor()316 void Cursor::selectPreviousCursor() {
317 	int16 newSequenceID = _sequenceID - 1;
318 	InventoryState inventoryType = _vm->_inventory->getState();
319 	if (newSequenceID == 0 && (inventoryType == InventoryOpen || inventoryType == InventionBookOpen)) {
320 		newSequenceID = _sequenceID - 2;
321 	}
322 	_sequenceID = newSequenceID;
323 	if (_sequenceID == 3 && inventoryType == InventoryOpen) {
324 		_sequenceID = 1;
325 	}
326 	if (_sequenceID == 2) {
327 		_sequenceID = 1;
328 	}
329 	if (_sequenceID == -1) {
330 		_sequenceID = _iniItemInHand == 0 ? 4 : 5;
331 	}
332 }
333 
updateSequenceID(int16 sequenceID)334 void Cursor::updateSequenceID(int16 sequenceID) {
335 	_sequenceID = sequenceID;
336 	_actor->updateSequence(_sequenceID);
337 }
338 
setActorFlag400()339 void Cursor::setActorFlag400() {
340 	_actor->setFlag(ACTOR_FLAG_400);
341 }
342 
clearActorFlag400()343 void Cursor::clearActorFlag400() {
344 	_actor->clearFlag(ACTOR_FLAG_400);
345 }
346 
getPalette()347 byte *Cursor::getPalette() {
348 	return _actor->_actorResource->getPalette();
349 }
350 
updateActorPosition(int16 x,int16 y)351 void Cursor::updateActorPosition(int16 x, int16 y) {
352 	updatePosition(x, y);
353 	_actor->_x_pos = _x;
354 	_actor->_y_pos = _y;
355 }
356 
357 } // End of namespace Dragons
358