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 "parallaction/exec.h"
24 #include "parallaction/input.h"
25 #include "parallaction/parallaction.h"
26 #include "parallaction/sound.h"
27
28 #include "common/textconsole.h"
29
30 namespace Parallaction {
31
32 #define INST_ON 1
33 #define INST_OFF 2
34 #define INST_X 3
35 #define INST_Y 4
36 #define INST_Z 5
37 #define INST_F 6
38 #define INST_LOOP 7
39 #define INST_ENDLOOP 8
40 #define INST_SHOW 9
41 #define INST_INC 10
42 #define INST_DEC 11
43 #define INST_SET 12
44 #define INST_PUT 13
45 #define INST_CALL 14
46 #define INST_WAIT 15
47 #define INST_START 16
48 #define INST_SOUND 17
49 #define INST_MOVE 18
50 #define INST_ENDSCRIPT 19
51
52 #define SetOpcodeTable(x) table = &x;
53
54
55
56 typedef Common::Functor1Mem<CommandContext&, void, CommandExec_ns> OpcodeV1;
57 #define COMMAND_OPCODE(op) table->push_back(new OpcodeV1(this, &CommandExec_ns::cmdOp_##op))
58 #define DECLARE_COMMAND_OPCODE(op) void CommandExec_ns::cmdOp_##op(CommandContext& ctxt)
59
60 typedef Common::Functor1Mem<ProgramContext&, void, ProgramExec_ns> OpcodeV2;
61 #define INSTRUCTION_OPCODE(op) table->push_back(new OpcodeV2(this, &ProgramExec_ns::instOp_##op))
62 #define DECLARE_INSTRUCTION_OPCODE(op) void ProgramExec_ns::instOp_##op(ProgramContext& ctxt)
63
64 extern const char *_instructionNamesRes_ns[];
65
66
DECLARE_INSTRUCTION_OPCODE(on)67 DECLARE_INSTRUCTION_OPCODE(on) {
68 InstructionPtr inst = ctxt._inst;
69
70 inst->_a->_flags |= kFlagsActive;
71 inst->_a->_flags &= ~kFlagsRemove;
72 }
73
74
DECLARE_INSTRUCTION_OPCODE(off)75 DECLARE_INSTRUCTION_OPCODE(off) {
76 ctxt._inst->_a->_flags |= kFlagsRemove;
77 }
78
79
DECLARE_INSTRUCTION_OPCODE(loop)80 DECLARE_INSTRUCTION_OPCODE(loop) {
81 InstructionPtr inst = ctxt._inst;
82
83 ctxt._program->_loopCounter = inst->_opB.getValue();
84 ctxt._program->_loopStart = ctxt._ip;
85 }
86
87
DECLARE_INSTRUCTION_OPCODE(endloop)88 DECLARE_INSTRUCTION_OPCODE(endloop) {
89 if (--ctxt._program->_loopCounter > 0) {
90 ctxt._ip = ctxt._program->_loopStart;
91 }
92 }
93
DECLARE_INSTRUCTION_OPCODE(inc)94 DECLARE_INSTRUCTION_OPCODE(inc) {
95 InstructionPtr inst = ctxt._inst;
96 int16 _si = inst->_opB.getValue();
97
98 if (inst->_flags & kInstMod) { // mod
99 int16 _bx = (_si > 0 ? _si : -_si);
100 if (ctxt._modCounter % _bx != 0) return;
101
102 _si = (_si > 0 ? 1 : -1);
103 }
104
105 int16 lvalue = inst->_opA.getValue();
106
107 if (inst->_index == INST_INC) {
108 lvalue += _si;
109 } else {
110 lvalue -= _si;
111 }
112
113 inst->_opA.setValue(lvalue);
114
115 }
116
117
DECLARE_INSTRUCTION_OPCODE(set)118 DECLARE_INSTRUCTION_OPCODE(set) {
119 ctxt._inst->_opA.setValue(ctxt._inst->_opB.getValue());
120 }
121
122
DECLARE_INSTRUCTION_OPCODE(put)123 DECLARE_INSTRUCTION_OPCODE(put) {
124 InstructionPtr inst = ctxt._inst;
125 Common::Rect r;
126 inst->_a->getFrameRect(r);
127
128 Graphics::Surface v18;
129 v18.init(r.width(), r.height(), r.width(), inst->_a->getFrameData(), Graphics::PixelFormat::createFormatCLUT8());
130
131 int16 x = inst->_opA.getValue();
132 int16 y = inst->_opB.getValue();
133 bool mask = (inst->_flags & kInstMaskedPut) == kInstMaskedPut;
134
135 _vm->_gfx->patchBackground(v18, x, y, mask);
136 }
137
DECLARE_INSTRUCTION_OPCODE(show)138 DECLARE_INSTRUCTION_OPCODE(show) {
139 ctxt._suspend = true;
140 }
141
DECLARE_INSTRUCTION_OPCODE(invalid)142 DECLARE_INSTRUCTION_OPCODE(invalid) {
143 error("Can't execute invalid opcode %i", ctxt._inst->_index);
144 }
145
DECLARE_INSTRUCTION_OPCODE(call)146 DECLARE_INSTRUCTION_OPCODE(call) {
147 _vm->callFunction(ctxt._inst->_immediate, 0);
148 }
149
150
DECLARE_INSTRUCTION_OPCODE(wait)151 DECLARE_INSTRUCTION_OPCODE(wait) {
152 if (g_engineFlags & kEngineWalking) {
153 ctxt._ip--;
154 ctxt._suspend = true;
155 }
156 }
157
158
DECLARE_INSTRUCTION_OPCODE(start)159 DECLARE_INSTRUCTION_OPCODE(start) {
160 ctxt._inst->_a->_flags |= (kFlagsActing | kFlagsActive);
161 }
162
163
DECLARE_INSTRUCTION_OPCODE(sound)164 DECLARE_INSTRUCTION_OPCODE(sound) {
165 _vm->_activeZone = ctxt._inst->_z;
166 }
167
168
DECLARE_INSTRUCTION_OPCODE(move)169 DECLARE_INSTRUCTION_OPCODE(move) {
170 InstructionPtr inst = ctxt._inst;
171
172 int16 x = inst->_opA.getValue();
173 int16 y = inst->_opB.getValue();
174
175 _vm->scheduleWalk(x, y, false);
176 }
177
DECLARE_INSTRUCTION_OPCODE(endscript)178 DECLARE_INSTRUCTION_OPCODE(endscript) {
179 if ((ctxt._anim->_flags & kFlagsLooping) == 0) {
180 ctxt._anim->_flags &= ~kFlagsActing;
181 _vm->_cmdExec->run(ctxt._anim->_commands, ctxt._anim);
182 ctxt._program->_status = kProgramDone;
183 }
184
185 ctxt._ip = 0;
186 ctxt._suspend = true;
187 }
188
189
190
191
DECLARE_COMMAND_OPCODE(invalid)192 DECLARE_COMMAND_OPCODE(invalid) {
193 error("Can't execute invalid command '%i'", ctxt._cmd->_id);
194 }
195
DECLARE_COMMAND_OPCODE(set)196 DECLARE_COMMAND_OPCODE(set) {
197 if (ctxt._cmd->_flags & kFlagsGlobal) {
198 ctxt._cmd->_flags &= ~kFlagsGlobal;
199 g_globalFlags |= ctxt._cmd->_flags;
200 } else {
201 _vm->setLocationFlags(ctxt._cmd->_flags);
202 }
203 }
204
205
DECLARE_COMMAND_OPCODE(clear)206 DECLARE_COMMAND_OPCODE(clear) {
207 if (ctxt._cmd->_flags & kFlagsGlobal) {
208 ctxt._cmd->_flags &= ~kFlagsGlobal;
209 g_globalFlags &= ~ctxt._cmd->_flags;
210 } else {
211 _vm->clearLocationFlags(ctxt._cmd->_flags);
212 }
213 }
214
215
DECLARE_COMMAND_OPCODE(start)216 DECLARE_COMMAND_OPCODE(start) {
217 ctxt._cmd->_zone->_flags |= kFlagsActing;
218 }
219
220
DECLARE_COMMAND_OPCODE(speak)221 DECLARE_COMMAND_OPCODE(speak) {
222 if (ACTIONTYPE(ctxt._cmd->_zone) == kZoneSpeak) {
223 _vm->enterDialogueMode(ctxt._cmd->_zone);
224 } else {
225 _vm->_activeZone = ctxt._cmd->_zone;
226 }
227 }
228
229
DECLARE_COMMAND_OPCODE(get)230 DECLARE_COMMAND_OPCODE(get) {
231 ctxt._cmd->_zone->_flags &= ~kFlagsFixed;
232 _vm->runZone(ctxt._cmd->_zone);
233 }
234
235
DECLARE_COMMAND_OPCODE(location)236 DECLARE_COMMAND_OPCODE(location) {
237 _vm->scheduleLocationSwitch(ctxt._cmd->_string.c_str());
238 }
239
240
DECLARE_COMMAND_OPCODE(open)241 DECLARE_COMMAND_OPCODE(open) {
242 _vm->updateDoor(ctxt._cmd->_zone, false);
243 }
244
245
DECLARE_COMMAND_OPCODE(close)246 DECLARE_COMMAND_OPCODE(close) {
247 _vm->updateDoor(ctxt._cmd->_zone, true);
248 }
249
DECLARE_COMMAND_OPCODE(on)250 DECLARE_COMMAND_OPCODE(on) {
251 _vm->showZone(ctxt._cmd->_zone, true);
252 }
253
254
DECLARE_COMMAND_OPCODE(off)255 DECLARE_COMMAND_OPCODE(off) {
256 _vm->showZone(ctxt._cmd->_zone, false);
257 }
258
259
DECLARE_COMMAND_OPCODE(call)260 DECLARE_COMMAND_OPCODE(call) {
261 _vm->callFunction(ctxt._cmd->_callable, &ctxt._z);
262 }
263
264
DECLARE_COMMAND_OPCODE(toggle)265 DECLARE_COMMAND_OPCODE(toggle) {
266 if (ctxt._cmd->_flags & kFlagsGlobal) {
267 ctxt._cmd->_flags &= ~kFlagsGlobal;
268 g_globalFlags ^= ctxt._cmd->_flags;
269 } else {
270 _vm->toggleLocationFlags(ctxt._cmd->_flags);
271 }
272 }
273
274
DECLARE_COMMAND_OPCODE(drop)275 DECLARE_COMMAND_OPCODE(drop){
276 _vm->dropItem( ctxt._cmd->_object );
277 }
278
279
DECLARE_COMMAND_OPCODE(quit)280 DECLARE_COMMAND_OPCODE(quit) {
281 _vm->quitGame();
282 }
283
284
DECLARE_COMMAND_OPCODE(move)285 DECLARE_COMMAND_OPCODE(move) {
286 _vm->scheduleWalk(ctxt._cmd->_move.x, ctxt._cmd->_move.y, false);
287 }
288
289
DECLARE_COMMAND_OPCODE(stop)290 DECLARE_COMMAND_OPCODE(stop) {
291 ctxt._cmd->_zone->_flags &= ~kFlagsActing;
292 }
293
CommandExec_ns(Parallaction_ns * vm)294 CommandExec_ns::CommandExec_ns(Parallaction_ns* vm) : CommandExec(vm), _vm(vm) {
295 CommandOpcodeSet *table = 0;
296
297 SetOpcodeTable(_opcodes);
298 COMMAND_OPCODE(invalid);
299 COMMAND_OPCODE(set);
300 COMMAND_OPCODE(clear);
301 COMMAND_OPCODE(start);
302 COMMAND_OPCODE(speak);
303 COMMAND_OPCODE(get);
304 COMMAND_OPCODE(location);
305 COMMAND_OPCODE(open);
306 COMMAND_OPCODE(close);
307 COMMAND_OPCODE(on);
308 COMMAND_OPCODE(off);
309 COMMAND_OPCODE(call);
310 COMMAND_OPCODE(toggle);
311 COMMAND_OPCODE(drop);
312 COMMAND_OPCODE(quit);
313 COMMAND_OPCODE(move);
314 COMMAND_OPCODE(stop);
315 }
316
ProgramExec_ns(Parallaction_ns * vm)317 ProgramExec_ns::ProgramExec_ns(Parallaction_ns *vm) : _vm(vm) {
318 _instructionNames = _instructionNamesRes_ns;
319
320 ProgramOpcodeSet *table = 0;
321
322 SetOpcodeTable(_opcodes);
323 INSTRUCTION_OPCODE(invalid);
324 INSTRUCTION_OPCODE(on);
325 INSTRUCTION_OPCODE(off);
326 INSTRUCTION_OPCODE(set); // x
327 INSTRUCTION_OPCODE(set); // y
328 INSTRUCTION_OPCODE(set); // z
329 INSTRUCTION_OPCODE(set); // f
330 INSTRUCTION_OPCODE(loop);
331 INSTRUCTION_OPCODE(endloop);
332 INSTRUCTION_OPCODE(show);
333 INSTRUCTION_OPCODE(inc);
334 INSTRUCTION_OPCODE(inc); // dec
335 INSTRUCTION_OPCODE(set);
336 INSTRUCTION_OPCODE(put);
337 INSTRUCTION_OPCODE(call);
338 INSTRUCTION_OPCODE(wait);
339 INSTRUCTION_OPCODE(start);
340 INSTRUCTION_OPCODE(sound);
341 INSTRUCTION_OPCODE(move);
342 INSTRUCTION_OPCODE(endscript);
343 }
344
345 } // namespace Parallaction
346