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 #ifndef CINE_SCRIPT_H
24 #define CINE_SCRIPT_H
25 
26 #include "common/savefile.h"
27 #include "common/array.h"
28 #include "common/list.h"
29 #include "common/ptr.h"
30 
31 namespace Cine {
32 
33 #define SCRIPT_STACK_SIZE 50
34 #define LOCAL_VARS_SIZE 50
35 
36 /**
37  * Fixed size array of script variables.
38  *
39  * Array size can be set in constructors, once the instance is created,
40  * it cannot be changed directly.
41  */
42 
43 class FWScript;
44 
45 typedef int (FWScript::*OpFunc)();
46 
47 struct Opcode {
48 	OpFunc proc;
49 	const char *args;
50 };
51 
52 /**
53  *  Fixed size array for script variables
54  */
55 class ScriptVars {
56 private:
57 	unsigned int _size; ///< Size of array
58 	int16 *_vars; ///< Variable values
59 
60 public:
61 	// Explicit to prevent var=0 instead of var[i]=0 typos.
62 	explicit ScriptVars(unsigned int len = 50);
63 	ScriptVars(Common::SeekableReadStream &fHandle, unsigned int len = 50);
64 	ScriptVars(const ScriptVars &src);
65 	~ScriptVars();
66 
67 	void reinit(unsigned int len);
68 	ScriptVars &operator=(const ScriptVars &src);
69 	int16 &operator[](unsigned int idx);
70 	int16 operator[](unsigned int idx) const;
71 
72 	void save(Common::OutSaveFile &fHandle) const;
73 	void save(Common::OutSaveFile &fHandle, unsigned int len) const;
74 	void load(Common::SeekableReadStream &fHandle);
75 	void load(Common::SeekableReadStream &fHandle, unsigned int len);
76 	void reset();
77 };
78 
79 class FWScriptInfo;
80 
81 /**
82  *  Script bytecode and initial labels, ScriptStruct replacement.
83  *
84  * _data is one byte longer to make sure strings in bytecode are properly
85  * terminated
86  */
87 class RawScript {
88 private:
89 	byte *_data; ///< Script bytecode
90 	ScriptVars _labels; ///< Initial script labels
91 
92 protected:
93 	void computeLabels(const FWScriptInfo &info);
94 	int getNextLabel(const FWScriptInfo &info, int offset) const;
95 
96 public:
97 	uint16 _size; ///< Bytecode length
98 
99 	explicit RawScript(uint16 size);
100 	RawScript(const FWScriptInfo &info, const byte *data, uint16 size);
101 	RawScript(const RawScript &src);
102 	~RawScript();
103 
104 	RawScript &operator=(const RawScript &src);
105 
106 	void setData(const FWScriptInfo &info, const byte *data);
107 	const ScriptVars &labels() const;
108 	byte getByte(unsigned int pos) const;
109 	uint16 getWord(unsigned int pos) const;
110 	const char *getString(unsigned int pos) const;
111 	uint16 getLabel(const FWScriptInfo &info, byte index, uint16 offset) const;
112 };
113 
114 /**
115  * Object script class, RelObjectScript replacement
116  *
117  * Script parameters are not used, this class is required by different
118  * script initialization of object scripts
119  */
120 class RawObjectScript : public RawScript {
121 public:
122 	int16 _runCount; ///< How many times the script was used
123 	uint16 _param1; ///< Additional parameter not used at the moment
124 	uint16 _param2; ///< Additional parameter not used at the moment
125 	uint16 _param3; ///< Additional parameter not used at the moment
126 
127 	RawObjectScript(uint16 size, uint16 p1, uint16 p2, uint16 p3);
128 	RawObjectScript(const FWScriptInfo &info, const byte *data, uint16 size, uint16 p1, uint16 p2, uint16 p3);
129 
130 	/**
131 	 * Run the script one more time.
132 	 * @return Run count before incrementation
133 	 */
run()134 	int16 run() { return _runCount++; }
135 };
136 
137 /**
138  * Future Wars script, prcLinkedListStruct replacement.
139  * @todo Rewrite _globalVars initialization
140  */
141 class FWScript {
142 private:
143 	const RawScript &_script; ///< Script bytecode reference
144 	uint16 _pos; ///< Current position in script
145 	uint16 _line; ///< Current opcode index in bytecode for debugging
146 	uint16 _compare; ///< Last compare result
147 	ScriptVars _labels; ///< Current script labels
148 	ScriptVars _localVars; ///< Local script variables
149 	ScriptVars &_globalVars; ///< Global variables reference
150 	FWScriptInfo *_info; ///< Script info
151 
152 protected:
153 	static const Opcode *_opcodeTable;
154 	static unsigned int _numOpcodes;
155 
156 	int o1_modifyObjectParam();
157 	int o1_getObjectParam();
158 	int o1_addObjectParam();
159 	int o1_subObjectParam();
160 	int o1_mulObjectParam();
161 	int o1_divObjectParam();
162 	int o1_compareObjectParam();
163 	int o1_setupObject();
164 	int o1_checkCollision();
165 	int o1_loadVar();
166 	int o1_addVar();
167 	int o1_subVar();
168 	int o1_mulVar();
169 	int o1_divVar();
170 	int o1_compareVar();
171 	int o1_modifyObjectParam2();
172 	int o1_loadMask0();
173 	int o1_unloadMask0();
174 	int o1_addToBgList();
175 	int o1_loadMask1();
176 	int o1_unloadMask1();
177 	int o1_loadMask4();
178 	int o1_unloadMask4();
179 	int o1_addSpriteFilledToBgList();
180 	int o1_clearBgIncrustList();
181 	int o1_label();
182 	int o1_goto();
183 	int o1_gotoIfSup();
184 	int o1_gotoIfSupEqu();
185 	int o1_gotoIfInf();
186 	int o1_gotoIfInfEqu();
187 	int o1_gotoIfEqu();
188 	int o1_gotoIfDiff();
189 	int o1_removeLabel();
190 	int o1_loop();
191 	int o1_startGlobalScript();
192 	int o1_endGlobalScript();
193 	int o1_loadAnim();
194 	int o1_loadBg();
195 	int o1_loadCt();
196 	int o1_loadPart();
197 	int o1_closePart();
198 	int o1_loadNewPrcName();
199 	int o1_requestCheckPendingDataLoad();
200 	int o1_blitAndFade();
201 	int o1_fadeToBlack();
202 	int o1_transformPaletteRange();
203 	int o1_setDefaultMenuBgColor();
204 	int o1_palRotate();
205 	int o1_break();
206 	int o1_endScript();
207 	int o1_message();
208 	int o1_loadGlobalVar();
209 	int o1_compareGlobalVar();
210 	int o1_declareFunctionName();
211 	int o1_freePartRange();
212 	int o1_unloadAllMasks();
213 	int o1_setScreenDimensions();
214 	int o1_displayBackground();
215 	int o1_initializeZoneData();
216 	int o1_setZoneDataEntry();
217 	int o1_getZoneDataEntry();
218 	int o1_setPlayerCommandPosY();
219 	int o1_allowPlayerInput();
220 	int o1_disallowPlayerInput();
221 	int o1_changeDataDisk();
222 	int o1_loadMusic();
223 	int o1_playMusic();
224 	int o1_fadeOutMusic();
225 	int o1_stopSample();
226 	int o1_op71();
227 	int o1_op72();
228 	int o1_op73();
229 	int o1_playSample();
230 	int o1_playSampleSwapped();
231 	int o1_disableSystemMenu();
232 	int o1_loadMask5();
233 	int o1_unloadMask5();
234 
235 	// pointers to member functions in C++ suck...
236 	int o2_loadCt();
237 	int o2_loadPart();
238 	int o2_addSeqListElement();
239 	int o2_removeSeq();
240 	int o2_playSample();
241 	int o2_playSampleAlt();
242 	int o2_clearSeqList();
243 	int o2_modifySeqListElement();
244 	int o2_isSeqRunning();
245 	int o2_gotoIfSupNearest();
246 	int o2_gotoIfSupEquNearest();
247 	int o2_gotoIfInfNearest();
248 	int o2_gotoIfInfEquNearest();
249 	int o2_gotoIfEquNearest();
250 	int o2_gotoIfDiffNearest();
251 	int o2_startObjectScript();
252 	int o2_stopObjectScript();
253 	int o2_op8D();
254 	int o2_addBackground();
255 	int o2_removeBackground();
256 	int o2_loadAbs();
257 	int o2_loadBg();
258 	int o2_wasZoneChecked();
259 	int o2_op9B();
260 	int o2_op9C();
261 	int o2_useBgScroll();
262 	int o2_setAdditionalBgVScroll();
263 	int o2_op9F();
264 	int o2_addGfxElementType20();
265 	int o2_removeGfxElementType20();
266 	int o2_addGfxElementType21();
267 	int o2_removeGfxElementType21();
268 	int o2_loadMask22();
269 	int o2_unloadMask22();
270 
271 	byte getNextByte();
272 	uint16 getNextWord();
273 	const char *getNextString();
274 
275 	void load(const ScriptVars &labels, const ScriptVars &local, uint16 compare, uint16 pos);
276 
277 	FWScript(const RawScript &script, int16 index, FWScriptInfo *info);
278 	FWScript(RawObjectScript &script, int16 index, FWScriptInfo *info);
279 	FWScript(const FWScript &src, FWScriptInfo *info);
280 
281 public:
282 	int16 _index; ///< Index in script table
283 
284 	static void setupTable();
285 
286 	FWScript(const RawScript &script, int16 index);
287 //	FWScript(const RawObjectScript &script, int16 index);
288 	FWScript(const FWScript &src);
289 	~FWScript();
290 
291 	int execute();
292 	void save(Common::OutSaveFile &fHandle) const;
293 
294 	friend class FWScriptInfo;
295 
296 	// workaround for bug in g++ which prevents protected member functions
297 	// of FWScript from being used in OSScript::_opcodeTable[]
298 	// initialization ("error: protected within this context")
299 	friend class OSScript;
300 };
301 
302 /**
303  * Operation Stealth script, prcLinkedListStruct replacement
304  */
305 class OSScript : public FWScript {
306 private:
307 	static const Opcode *_opcodeTable;
308 	static unsigned int _numOpcodes;
309 
310 protected:
311 	void load(const ScriptVars &labels, const ScriptVars &local, uint16 compare, uint16 pos);
312 
313 public:
314 	static void setupTable();
315 
316 	OSScript(const RawScript &script, int16 index);
317 	OSScript(RawObjectScript &script, int16 index);
318 	OSScript(const OSScript &src);
319 
320 	friend class OSScriptInfo;
321 };
322 
323 /**
324  * Future Wars script factory and info
325  */
326 class FWScriptInfo {
327 protected:
328 	virtual OpFunc opcodeHandler(byte opcode) const;
329 
330 public:
~FWScriptInfo()331 	virtual ~FWScriptInfo() {}
332 
333 	virtual const char *opcodeInfo(byte opcode) const;
334 	virtual FWScript *create(const RawScript &script, int16 index) const;
335 	virtual FWScript *create(const RawObjectScript &script, int16 index) const;
336 	virtual FWScript *create(const RawScript &script, int16 index, const ScriptVars &labels, const ScriptVars &local, uint16 compare, uint16 pos) const;
337 	virtual FWScript *create(const RawObjectScript &script, int16 index, const ScriptVars &labels, const ScriptVars &local, uint16 compare, uint16 pos) const;
338 
339 	friend class FWScript;
340 };
341 
342 /**
343  * Operation Stealth script factory and info
344  */
345 class OSScriptInfo : public FWScriptInfo {
346 protected:
347 	OpFunc opcodeHandler(byte opcode) const override;
348 
349 public:
~OSScriptInfo()350 	~OSScriptInfo() override {}
351 
352 	const char *opcodeInfo(byte opcode) const override;
353 	FWScript *create(const RawScript &script, int16 index) const override;
354 	FWScript *create(const RawObjectScript &script, int16 index) const override;
355 	FWScript *create(const RawScript &script, int16 index, const ScriptVars &labels, const ScriptVars &local, uint16 compare, uint16 pos) const override;
356 	FWScript *create(const RawObjectScript &script, int16 index, const ScriptVars &labels, const ScriptVars &local, uint16 compare, uint16 pos) const override;
357 
358 	friend class FWScript;
359 };
360 
361 typedef Common::SharedPtr<FWScript> ScriptPtr;
362 typedef Common::SharedPtr<RawScript> RawScriptPtr;
363 typedef Common::SharedPtr<RawObjectScript> RawObjectScriptPtr;
364 typedef Common::List<ScriptPtr> ScriptList;
365 typedef Common::Array<RawScriptPtr> RawScriptArray;
366 typedef Common::Array<RawObjectScriptPtr> RawObjectScriptArray;
367 
368 #define NUM_MAX_SCRIPT 50
369 
370 extern FWScriptInfo *scriptInfo;
371 
372 void setupOpcodes();
373 
374 void decompileScript(const byte *scriptPtr, uint16 scriptSize, uint16 scriptIdx);
375 void dumpScript(char *dumpName);
376 
377 #define OP_loadPart                     0x3F
378 #define OP_loadNewPrcName               0x41
379 #define OP_requestCheckPendingDataLoad  0x42
380 #define OP_endScript                    0x50
381 
382 void addScriptToGlobalScripts(uint16 idx);
383 int16 checkCollision(int16 objIdx, int16 x, int16 y, int16 numZones, int16 zoneIdx);
384 
385 void runObjectScript(int16 entryIdx);
386 
387 void executeObjectScripts();
388 void executeGlobalScripts();
389 
390 void purgeObjectScripts();
391 void purgeGlobalScripts();
392 
393 } // End of namespace Cine
394 
395 #endif
396