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 "illusions/illusions.h"
24 #include "illusions/sequenceopcodes.h"
25 #include "illusions/actor.h"
26 #include "illusions/dictionary.h"
27 #include "illusions/resources/actorresource.h"
28 #include "illusions/screen.h"
29 #include "illusions/scriptopcodes.h"
30 #include "illusions/sound.h"
31 
32 namespace Illusions {
33 
34 // SequenceOpcodes
35 
SequenceOpcodes(IllusionsEngine * vm)36 SequenceOpcodes::SequenceOpcodes(IllusionsEngine *vm)
37 	: _vm(vm) {
38 	initOpcodes();
39 }
40 
~SequenceOpcodes()41 SequenceOpcodes::~SequenceOpcodes() {
42 	freeOpcodes();
43 }
44 
execOpcode(Control * control,OpCall & opCall)45 void SequenceOpcodes::execOpcode(Control *control, OpCall &opCall) {
46 	if (!_opcodes[opCall._op])
47 		error("SequenceOpcodes::execOpcode() Unimplemented opcode %d", opCall._op);
48 	debug(3, "execSequenceOpcode(%d) %s objectID: %08X", opCall._op, _opcodeNames[opCall._op].c_str(), control->_objectId);
49 	(*_opcodes[opCall._op])(control, opCall);
50 }
51 
52 typedef Common::Functor2Mem<Control*, OpCall&, void, SequenceOpcodes> SequenceOpcodeI;
53 #define OPCODE(op, func) \
54 	_opcodes[op] = new SequenceOpcodeI(this, &SequenceOpcodes::func); \
55 	_opcodeNames[op] = #func;
56 
initOpcodes()57 void SequenceOpcodes::initOpcodes() {
58 	// First clear everything
59 	for (uint i = 0; i < 256; ++i) {
60 		_opcodes[i] = 0;
61 	}
62 	// Register opcodes
63 	OPCODE(1, opYield);
64 	OPCODE(2, opSetFrameIndex);
65 	OPCODE(3, opEndSequence);
66 	OPCODE(4, opIncFrameDelay);
67 	OPCODE(5, opSetRandomFrameDelay);
68 	OPCODE(6, opSetFrameSpeed);
69 	OPCODE(7, opJump);
70 	OPCODE(8, opJumpRandom);
71 	OPCODE(9, opGotoSequence);
72 	OPCODE(10, opStartForeignSequence);
73 	OPCODE(11, opBeginLoop);
74 	OPCODE(12, opNextLoop);
75 	OPCODE(13, opSetActorIndex);
76 	OPCODE(14, opSwitchActorIndex);
77 	OPCODE(15, opSwitchFacing);
78 	OPCODE(16, opAppearActor);
79 	OPCODE(17, opDisappearActor);
80 	OPCODE(18, opAppearForeignActor);
81 	OPCODE(19, opDisappearForeignActor);
82 	OPCODE(20, opSetNamedPointPosition);
83 	OPCODE(21, opMoveDelta);
84 	// 22-24 unused in Duckman, CHECKME BBDOU
85 	OPCODE(25, opFaceActor);
86 	// 26-27 unused in Duckman, CHECKME BBDOU
87 	OPCODE(28, opNotifyThreadId1);
88 	OPCODE(29, opSetPathCtrY);
89 	// 30-31 unused in Duckman, CHECKME BBDOU
90 	OPCODE(32, opDisablePathWalkPoints);
91 	OPCODE(33, opSetPathWalkPoints);
92 	OPCODE(34, opDisableAutoScale);
93 	OPCODE(35, opSetScale);
94 	OPCODE(36, opSetScaleLayer);
95 	OPCODE(37, opDeactivatePathWalkRects);
96 	OPCODE(38, opSetPathWalkRects);
97 	OPCODE(39, opSetPriority);
98 	OPCODE(40, opSetPriorityLayer);
99 	OPCODE(41, opDisableAutoRegionLayer);
100 	OPCODE(42, opSetRegionLayer);
101 	// 43-47 unused in Duckman, CHECKME BBDOU
102 	OPCODE(48, opSetPalette);
103 	OPCODE(49, opShiftPalette);
104 	OPCODE(50, opPlaySound);
105 	OPCODE(51, opStopSound);
106 	OPCODE(52, opStartScriptThread);
107 	OPCODE(53, opPlaceSubActor);
108 	OPCODE(54, opStartSubSequence);
109 	OPCODE(55, opStopSubSequence);
110 }
111 
112 #undef OPCODE
113 
freeOpcodes()114 void SequenceOpcodes::freeOpcodes() {
115 	for (uint i = 0; i < 256; ++i) {
116 		delete _opcodes[i];
117 	}
118 }
119 
120 // Opcodes
121 
opYield(Control * control,OpCall & opCall)122 void SequenceOpcodes::opYield(Control *control, OpCall &opCall) {
123 	opCall._result = 2;
124 }
125 
opSetFrameIndex(Control * control,OpCall & opCall)126 void SequenceOpcodes::opSetFrameIndex(Control *control, OpCall &opCall) {
127 	ARG_INT16(frameIndex);
128 	if (control->_actor->_flags & Illusions::ACTOR_FLAG_80) {
129 		int16 frameIncr = READ_LE_UINT16(control->_actor->_entryTblPtr);
130 		if (frameIncr) {
131 			frameIndex += frameIncr - 1;
132 			control->_actor->_entryTblPtr += 2;
133 		} else {
134 			control->_actor->_flags &= ~Illusions::ACTOR_FLAG_80;
135 			control->_actor->_entryTblPtr = 0;
136 			control->_actor->_notifyThreadId2 = 0;
137 			_vm->notifyThreadId(control->_actor->_notifyThreadId1);
138 			opCall._result = 1;
139 		}
140 	}
141 	control->_actor->_flags &= ~Illusions::ACTOR_FLAG_100;
142 	if (control->_actor->_flags & Illusions::ACTOR_FLAG_8000) {
143 		control->appearActor();
144 		control->_actor->_flags &= ~Illusions::ACTOR_FLAG_8000;
145 	}
146 	control->_actor->_newFrameIndex = frameIndex;
147 }
148 
opEndSequence(Control * control,OpCall & opCall)149 void SequenceOpcodes::opEndSequence(Control *control, OpCall &opCall) {
150 	control->_actor->_seqCodeIp = 0;
151 	if (control->_actor->_flags & Illusions::ACTOR_FLAG_800) {
152 		control->_actor->_flags &= ~Illusions::ACTOR_FLAG_800;
153 		control->_actor->_frames = 0;
154 		control->_actor->_frameIndex = 0;
155 		control->_actor->_newFrameIndex = 0;
156 		_vm->_resSys->unloadResourceById(control->_actor->_sequenceId);
157 	}
158 	_vm->notifyThreadId(control->_actor->_notifyThreadId1);
159 	opCall._result = 1;
160 }
161 
opIncFrameDelay(Control * control,OpCall & opCall)162 void SequenceOpcodes::opIncFrameDelay(Control *control, OpCall &opCall) {
163 	ARG_INT16(frameDelayIncr);
164 	control->_actor->_seqCodeValue3 += frameDelayIncr;
165 	opCall._result = 2;
166 }
167 
opSetRandomFrameDelay(Control * control,OpCall & opCall)168 void SequenceOpcodes::opSetRandomFrameDelay(Control *control, OpCall &opCall) {
169 	ARG_INT16(minFrameDelay);
170 	ARG_INT16(maxFrameDelay);
171 	control->_actor->_seqCodeValue3 += minFrameDelay + _vm->getRandom(maxFrameDelay);
172 	opCall._result = 2;
173 }
174 
opSetFrameSpeed(Control * control,OpCall & opCall)175 void SequenceOpcodes::opSetFrameSpeed(Control *control, OpCall &opCall) {
176 	ARG_INT16(frameSpeed);
177 	control->_actor->_seqCodeValue2 = frameSpeed;
178 }
179 
opJump(Control * control,OpCall & opCall)180 void SequenceOpcodes::opJump(Control *control, OpCall &opCall) {
181 	ARG_INT16(jumpOffs);
182 	opCall._deltaOfs += jumpOffs;
183 }
184 
opJumpRandom(Control * control,OpCall & opCall)185 void SequenceOpcodes::opJumpRandom(Control *control, OpCall &opCall) {
186 	ARG_INT16(count);
187 	ARG_SKIP(_vm->getRandom(count) * 2);
188 	ARG_INT16(jumpOffs);
189 	opCall._deltaOfs += jumpOffs;
190 }
191 
opGotoSequence(Control * control,OpCall & opCall)192 void SequenceOpcodes::opGotoSequence(Control *control, OpCall &opCall) {
193 	ARG_SKIP(2);
194 	ARG_UINT32(nextSequenceId);
195 	uint32 notifyThreadId1 = control->_actor->_notifyThreadId1;
196 	control->clearNotifyThreadId1();
197 	if (control->_actor->_pathNode) {
198 		control->startSequenceActor(nextSequenceId, 1, notifyThreadId1);
199 	} else {
200 		control->startSequenceActor(nextSequenceId, 2, notifyThreadId1);
201 	}
202 	opCall._deltaOfs = 0;
203 }
204 
opStartForeignSequence(Control * control,OpCall & opCall)205 void SequenceOpcodes::opStartForeignSequence(Control *control, OpCall &opCall) {
206 	ARG_INT16(foreignObjectNum);
207 	ARG_UINT32(sequenceId);
208 	Control *foreignControl = _vm->_dict->getObjectControl(foreignObjectNum | 0x40000);
209 	foreignControl->startSequenceActor(sequenceId, 2, 0);
210 }
211 
opBeginLoop(Control * control,OpCall & opCall)212 void SequenceOpcodes::opBeginLoop(Control *control, OpCall &opCall) {
213 	ARG_INT16(loopCount);
214 	control->_actor->pushSequenceStack(loopCount);
215 }
216 
opNextLoop(Control * control,OpCall & opCall)217 void SequenceOpcodes::opNextLoop(Control *control, OpCall &opCall) {
218 	ARG_INT16(jumpOffs);
219 	int16 currLoopCount = control->_actor->popSequenceStack();
220 	if (currLoopCount > 0) {
221 		control->_actor->pushSequenceStack(currLoopCount - 1);
222 		opCall._deltaOfs = -jumpOffs;
223 	}
224 }
225 
opSetActorIndex(Control * control,OpCall & opCall)226 void SequenceOpcodes::opSetActorIndex(Control *control, OpCall &opCall) {
227 	ARG_BYTE(actorIndex);
228 	control->setActorIndex(actorIndex);
229 }
230 
opSwitchActorIndex(Control * control,OpCall & opCall)231 void SequenceOpcodes::opSwitchActorIndex(Control *control, OpCall &opCall) {
232 	ARG_INT16(actorIndex);
233 	ARG_INT16(jumpOffs);
234 	if (control->_actor->_actorIndex != actorIndex)
235 		opCall._deltaOfs += jumpOffs;
236 }
237 
opSwitchFacing(Control * control,OpCall & opCall)238 void SequenceOpcodes::opSwitchFacing(Control *control, OpCall &opCall) {
239 	ARG_INT16(facing);
240 	ARG_INT16(jumpOffs);
241 	if (!(control->_actor->_facing & facing))
242 		opCall._deltaOfs += jumpOffs;
243 }
244 
opAppearActor(Control * control,OpCall & opCall)245 void SequenceOpcodes::opAppearActor(Control *control, OpCall &opCall) {
246 	control->appearActor();
247 }
248 
opDisappearActor(Control * control,OpCall & opCall)249 void SequenceOpcodes::opDisappearActor(Control *control, OpCall &opCall) {
250 	control->disappearActor();
251 	control->_actor->_newFrameIndex = 0;
252 }
253 
opAppearForeignActor(Control * control,OpCall & opCall)254 void SequenceOpcodes::opAppearForeignActor(Control *control, OpCall &opCall) {
255 	ARG_INT16(foreignObjectNum);
256 	Control *foreignControl = _vm->_dict->getObjectControl(foreignObjectNum | 0x40000);
257 	if (!foreignControl) {
258 		Common::Point pos = _vm->getNamedPointPosition(_vm->getGameId() == kGameIdDuckman ? 0x00070001 : 0x00070023);
259 		_vm->_controls->placeActor(0x00050001, pos, 0x00060001, foreignObjectNum | 0x40000, 0);
260 		foreignControl = _vm->_dict->getObjectControl(foreignObjectNum | 0x40000);
261 	}
262 	foreignControl->appearActor();
263 }
264 
opDisappearForeignActor(Control * control,OpCall & opCall)265 void SequenceOpcodes::opDisappearForeignActor(Control *control, OpCall &opCall) {
266 	ARG_INT16(foreignObjectNum);
267 	Control *foreignControl = _vm->_dict->getObjectControl(foreignObjectNum | 0x40000);
268 	foreignControl->disappearActor();
269 }
270 
opSetNamedPointPosition(Control * control,OpCall & opCall)271 void SequenceOpcodes::opSetNamedPointPosition(Control *control, OpCall &opCall) {
272 	ARG_SKIP(2);
273 	ARG_UINT32(namedPointId);
274 	control->_actor->_position = _vm->getNamedPointPosition(namedPointId);
275 }
276 
opMoveDelta(Control * control,OpCall & opCall)277 void SequenceOpcodes::opMoveDelta(Control *control, OpCall &opCall) {
278 	ARG_SKIP(2);
279 	ARG_INT16(deltaX);
280 	ARG_INT16(deltaY);
281 	control->_actor->_position.x += deltaX;
282 	control->_actor->_position.y += deltaY;
283 }
284 
opFaceActor(Control * control,OpCall & opCall)285 void SequenceOpcodes::opFaceActor(Control *control, OpCall &opCall) {
286 	ARG_INT16(facing);
287 	control->_actor->_facing = facing;
288 }
289 
opNotifyThreadId1(Control * control,OpCall & opCall)290 void SequenceOpcodes::opNotifyThreadId1(Control *control, OpCall &opCall) {
291 	_vm->notifyThreadId(control->_actor->_notifyThreadId1);
292 }
293 
opSetPathCtrY(Control * control,OpCall & opCall)294 void SequenceOpcodes::opSetPathCtrY(Control *control, OpCall &opCall) {
295 	ARG_INT16(pathCtrY);
296 	control->_actor->_pathCtrY = pathCtrY;
297 }
298 
opDisablePathWalkPoints(Control * control,OpCall & opCall)299 void SequenceOpcodes::opDisablePathWalkPoints(Control *control, OpCall &opCall) {
300 	control->_actor->_flags &= ~Illusions::ACTOR_FLAG_HAS_WALK_POINTS;
301 }
302 
opSetPathWalkPoints(Control * control,OpCall & opCall)303 void SequenceOpcodes::opSetPathWalkPoints(Control *control, OpCall &opCall) {
304 	ARG_INT16(pathWalkPointsIndex);
305 	BackgroundResource *bgRes = _vm->_backgroundInstances->getActiveBgResource();
306 	control->_actor->_flags |= Illusions::ACTOR_FLAG_HAS_WALK_POINTS;
307 	control->_actor->_pathWalkPoints = bgRes->getPathWalkPoints(pathWalkPointsIndex - 1);
308 }
309 
opDisableAutoScale(Control * control,OpCall & opCall)310 void SequenceOpcodes::opDisableAutoScale(Control *control, OpCall &opCall) {
311 	// Keep current scale but don't autoscale
312 	control->_actor->_flags &= ~Illusions::ACTOR_FLAG_SCALED;
313 }
314 
opSetScale(Control * control,OpCall & opCall)315 void SequenceOpcodes::opSetScale(Control *control, OpCall &opCall) {
316 	ARG_INT16(scale);
317 	control->_actor->_flags &= ~Illusions::ACTOR_FLAG_SCALED;
318 	control->setActorScale(scale);
319 }
320 
opSetScaleLayer(Control * control,OpCall & opCall)321 void SequenceOpcodes::opSetScaleLayer(Control *control, OpCall &opCall) {
322 	ARG_INT16(scaleLayerIndex);
323 	BackgroundResource *bgRes = _vm->_backgroundInstances->getActiveBgResource();
324 	control->_actor->_flags |= Illusions::ACTOR_FLAG_SCALED;
325 	control->_actor->_scaleLayer = bgRes->getScaleLayer(scaleLayerIndex - 1);
326 	int scale = control->_actor->_scaleLayer->getScale(control->_actor->_position);
327 	control->setActorScale(scale);
328 }
329 
opDeactivatePathWalkRects(Control * control,OpCall & opCall)330 void SequenceOpcodes::opDeactivatePathWalkRects(Control *control, OpCall &opCall) {
331 	control->_actor->_flags &= ~Illusions::ACTOR_FLAG_HAS_WALK_RECTS;
332 }
333 
opSetPathWalkRects(Control * control,OpCall & opCall)334 void SequenceOpcodes::opSetPathWalkRects(Control *control, OpCall &opCall) {
335 	ARG_INT16(pathWalkRectsIndex);
336 	BackgroundResource *bgRes = _vm->_backgroundInstances->getActiveBgResource();
337 	control->_actor->_flags |= Illusions::ACTOR_FLAG_HAS_WALK_RECTS;
338 	control->_actor->_pathWalkRects = bgRes->getPathWalkRects(pathWalkRectsIndex - 1);
339 }
340 
opSetPriority(Control * control,OpCall & opCall)341 void SequenceOpcodes::opSetPriority(Control *control, OpCall &opCall) {
342 	ARG_INT16(priority);
343 	control->_actor->_flags &= ~Illusions::ACTOR_FLAG_PRIORITY;
344 	control->setPriority(priority);
345 }
346 
opSetPriorityLayer(Control * control,OpCall & opCall)347 void SequenceOpcodes::opSetPriorityLayer(Control *control, OpCall &opCall) {
348 	ARG_INT16(priorityLayerIndex);
349 	BackgroundResource *bgRes = _vm->_backgroundInstances->getActiveBgResource();
350 	control->_actor->_flags |= Illusions::ACTOR_FLAG_PRIORITY;
351 	control->_actor->_priorityLayer = bgRes->getPriorityLayer(priorityLayerIndex - 1);
352 	int priority = control->_actor->_priorityLayer->getPriority(control->_actor->_position);
353 	control->setPriority(priority);
354 }
355 
opDisableAutoRegionLayer(Control * control,OpCall & opCall)356 void SequenceOpcodes::opDisableAutoRegionLayer(Control *control, OpCall &opCall) {
357 	control->_actor->_flags &= ~Illusions::ACTOR_FLAG_REGION;
358 }
359 
opSetRegionLayer(Control * control,OpCall & opCall)360 void SequenceOpcodes::opSetRegionLayer(Control *control, OpCall &opCall) {
361 	ARG_INT16(regionLayerIndex);
362 	BackgroundResource *bgRes = _vm->_backgroundInstances->getActiveBgResource();
363 	control->_actor->_flags |= Illusions::ACTOR_FLAG_REGION;
364 	control->_actor->_regionLayer = bgRes->getRegionLayer(regionLayerIndex - 1);
365 }
366 
opSetPalette(Control * control,OpCall & opCall)367 void SequenceOpcodes::opSetPalette(Control *control, OpCall &opCall) {
368 	ARG_INT16(paletteIndex);
369 	ARG_BYTE(fromIndex);
370 	BackgroundResource *bgRes = _vm->_backgroundInstances->getActiveBgResource();
371 	Palette *palette = bgRes->getPalette(paletteIndex - 1);
372 	_vm->_screenPalette->setPalette(palette->_palette, fromIndex, palette->_count);
373 }
374 
opShiftPalette(Control * control,OpCall & opCall)375 void SequenceOpcodes::opShiftPalette(Control *control, OpCall &opCall) {
376 	ARG_INT16(fromIndex);
377 	ARG_INT16(toIndex);
378 	_vm->_screenPalette->shiftPalette(fromIndex, toIndex);
379 }
380 
opPlaySound(Control * control,OpCall & opCall)381 void SequenceOpcodes::opPlaySound(Control *control, OpCall &opCall) {
382 	ARG_INT16(flags);
383 	ARG_INT16(volume);
384 	ARG_INT16(pan);
385 	ARG_UINT32(soundEffectId);
386 	if (!(flags & 1))
387 		volume = 255;
388 	if (!(flags & 2))
389 		pan = _vm->convertPanXCoord(control->_actor->_position.x);
390 	_vm->_soundMan->playSound(soundEffectId, volume, pan);
391 }
392 
opStopSound(Control * control,OpCall & opCall)393 void SequenceOpcodes::opStopSound(Control *control, OpCall &opCall) {
394 	ARG_UINT32(soundEffectId);
395 	_vm->_soundMan->stopSound(soundEffectId);
396 }
397 
opStartScriptThread(Control * control,OpCall & opCall)398 void SequenceOpcodes::opStartScriptThread(Control *control, OpCall &opCall) {
399 	ARG_SKIP(2);
400 	ARG_UINT32(threadId);
401 	_vm->startScriptThreadSimple(threadId, 0);
402 }
403 
opPlaceSubActor(Control * control,OpCall & opCall)404 void SequenceOpcodes::opPlaceSubActor(Control *control, OpCall &opCall) {
405 	ARG_INT16(linkIndex);
406 	ARG_UINT32(actorTypeId);
407 	ARG_UINT32(sequenceId);
408 	_vm->_controls->placeSubActor(control->_objectId, linkIndex, actorTypeId, sequenceId);
409 }
410 
opStartSubSequence(Control * control,OpCall & opCall)411 void SequenceOpcodes::opStartSubSequence(Control *control, OpCall &opCall) {
412 	ARG_INT16(linkIndex);
413 	ARG_UINT32(sequenceId);
414 	control->startSubSequence(linkIndex, sequenceId);
415 }
416 
opStopSubSequence(Control * control,OpCall & opCall)417 void SequenceOpcodes::opStopSubSequence(Control *control, OpCall &opCall) {
418 	ARG_INT16(linkIndex);
419 	control->stopSubSequence(linkIndex);
420 }
421 
422 } // End of namespace Illusions
423