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/textconsole.h"
24 
25 #include "parallaction/parallaction.h"
26 #include "parallaction/objects.h"
27 #include "parallaction/parser.h"
28 
29 namespace Parallaction {
30 
31 
Command()32 Command::Command() {
33 	_id = 0;
34 	_flagsOn = 0;
35 	_flagsOff = 0;
36 	_valid = false;
37 
38 	_flags = 0;
39 	_callable = 0;
40 	_object = 0;
41 	_counterValue = 0;
42 	_zeta0 = 0;
43 	_zeta1 = 0;
44 	_zeta2 = 0;
45 	_characterId = 0;
46 	_musicCommand = 0;
47 	_musicParm = 0;
48 }
49 
Animation()50 Animation::Animation() {
51 	gfxobj = NULL;
52 	_frame = 0;
53 	_z = 0;
54 }
55 
~Animation()56 Animation::~Animation() {
57 	if (gfxobj) {
58 		gfxobj->release();
59 	}
60 }
61 
getFrameRect(Common::Rect & r) const62 void Animation::getFrameRect(Common::Rect &r) const {
63 	r.setWidth(0); r.setHeight(0);
64 	if (!gfxobj) {
65 		return;
66 	}
67 	gfxobj->getRect(_frame, r);
68 	r.translate(_left, _top);
69 }
70 
hitFrameRect(int x,int y) const71 bool Animation::hitFrameRect(int x, int y) const {
72 	if (!gfxobj) {
73 		return false;
74 	}
75 	Common::Rect r;
76 	getFrameRect(r);
77 	return r.contains(x, y);
78 }
79 
getBottom() const80 int16 Animation::getBottom() const {
81 	int bottom = _top;
82 	if (gfxobj) {
83 		Common::Rect r;
84 		getFrameRect(r);
85 		bottom = r.bottom;
86 	}
87 	return bottom;
88 }
89 
resetZ()90 void Animation::resetZ() {
91 	setZ(getBottom());
92 }
93 
getFrameNum() const94 uint16 Animation::getFrameNum() const {
95 	if (!gfxobj) return 0;
96 	return gfxobj->getNum();
97 }
98 
getFrameData() const99 byte* Animation::getFrameData() const {
100 	if (!gfxobj) return NULL;
101 	return gfxobj->getData(_frame);
102 }
103 
setF(int16 value)104 void Animation::setF(int16 value) {
105 	int16 min = MIN(0, getFrameNum() - 1);
106 	int16 max = MAX(0, getFrameNum() - 1);
107 	_frame = CLIP(value, min, max);
108 }
109 
forceXYZF(int16 x,int16 y,int16 z,int16 f)110 void Animation::forceXYZF(int16 x, int16 y, int16 z, int16 f) {
111 	_left = x;
112 	_top = y;
113 	_z = z;
114 	_frame = f;
115 }
116 
getFoot(Common::Point & foot)117 void Animation::getFoot(Common::Point &foot) {
118 	Common::Rect rect;
119 	gfxobj->getRect(_frame, rect);
120 	foot.x = getX() + (rect.left + rect.width() / 2);
121 	foot.y = getY() + (rect.top + rect.height());
122 }
123 
setFoot(const Common::Point & foot)124 void Animation::setFoot(const Common::Point &foot) {
125 	Common::Rect rect;
126 	gfxobj->getRect(_frame, rect);
127 
128 	setX(foot.x - (rect.left + rect.width() / 2));
129 	setY(foot.y - (rect.top + rect.height()));
130 }
131 
132 #define NUM_LOCALS	10
133 char	_localNames[NUM_LOCALS][10];
134 
Program()135 Program::Program() {
136 	_loopCounter = 0;
137 	_locals = new LocalVariable[NUM_LOCALS];
138 	_numLocals = 0;
139 	_status = kProgramIdle;
140 	_ip = 0;
141 	_loopStart = 0;
142 }
143 
~Program()144 Program::~Program() {
145 	delete[] _locals;
146 }
147 
findLocal(const char * name)148 int16 Program::findLocal(const char* name) {
149 	for (uint16 _si = 0; _si < NUM_LOCALS; _si++) {
150 		if (!scumm_stricmp(name, _localNames[_si]))
151 			return _si;
152 	}
153 
154 	return -1;
155 }
156 
addLocal(const char * name,int16 value,int16 min,int16 max)157 int16 Program::addLocal(const char *name, int16 value, int16 min, int16 max) {
158 	assert(_numLocals < NUM_LOCALS);
159 
160 	Common::strlcpy(_localNames[_numLocals], name, 10);
161 	_locals[_numLocals].setRange(min, max);
162 	_locals[_numLocals].setValue(value);
163 
164 	return _numLocals++;
165 }
166 
setValue(int16 value)167 void LocalVariable::setValue(int16 value) {
168 	if (value >= _max)
169 		value = _min;
170 	if (value < _min)
171 		value = _max - 1;
172 
173 	_value = value;
174 }
175 
setRange(int16 min,int16 max)176 void LocalVariable::setRange(int16 min, int16 max) {
177 	_max = max;
178 	_min = min;
179 }
180 
getValue() const181 int16 LocalVariable::getValue() const {
182 	return _value;
183 }
184 
185 
Zone()186 Zone::Zone() {
187 	_left = _top = _right = _bottom = 0;
188 
189 	_type = 0;
190 
191 	_flags = kFlagsNoName;
192 	_label = 0;
193 
194 	// BRA specific
195 	_index = INVALID_ZONE_INDEX;
196 	_locationIndex = INVALID_LOCATION_INDEX;
197 }
198 
~Zone()199 Zone::~Zone() {
200 	g_vm->_gfx->unregisterLabel(_label);
201 	delete _label;
202 }
203 
translate(int16 x,int16 y)204 void Zone::translate(int16 x, int16 y) {
205 	_left += x;
206 	_right += x;
207 	_top += y;
208 	_bottom += y;
209 }
210 
hitRect(int x,int y) const211 bool Zone::hitRect(int x, int y) const {
212 	// The scripts of Nippon Safes are full of invalid rectangles, used to
213 	// provide 'special' features.
214 	if (_right < _left || _bottom < _top) {
215 		return false;
216 	}
217 
218 	Common::Rect r(_left, _top, _right + 1, _bottom + 1);
219 	r.grow(-1);
220 
221 	return r.contains(x, y);
222 }
223 
Dialogue()224 Dialogue::Dialogue() {
225 	memset(_questions, 0, sizeof(_questions));
226 	_numQuestions = 0;
227 }
228 
~Dialogue()229 Dialogue::~Dialogue() {
230 	for (int i = 0; i < NUM_QUESTIONS; i++) {
231 		delete _questions[i];
232 	}
233 }
234 
findQuestion(const Common::String & name) const235 Question *Dialogue::findQuestion(const Common::String &name) const {
236 	for (uint i = 0; _questions[i]; ++i) {
237 		if (_questions[i]->_name == name) {
238 			return _questions[i];
239 		}
240 	}
241 	return 0;
242 }
243 
addQuestion(Question * q)244 void Dialogue::addQuestion(Question *q) {
245 	assert(_numQuestions < NUM_QUESTIONS);
246 	assert(q);
247 	_questions[_numQuestions] = q;
248 	_numQuestions++;
249 }
250 
Answer()251 Answer::Answer() {
252 	_mood = 0;
253 	_noFlags = 0;
254 	_yesFlags = 0;
255 	_hasCounterCondition = false;
256 	_counterValue = 0;
257 	_counterOp = 0;
258 }
259 
textIsNull()260 bool Answer::textIsNull() {
261 	return (_text.equalsIgnoreCase("NULL"));
262 }
263 
speakerMood()264 int Answer::speakerMood() {
265 	return _mood & 0xF;
266 }
267 
Question(const Common::String & name)268 Question::Question(const Common::String &name) : _name(name), _mood(0) {
269 	memset(_answers, 0, sizeof(_answers));
270 }
271 
~Question()272 Question::~Question() {
273 	for (uint32 i = 0; i < NUM_ANSWERS; i++) {
274 		delete _answers[i];
275 	}
276 }
277 
textIsNull()278 bool Question::textIsNull() {
279 	return (_text.equalsIgnoreCase("NULL"));
280 }
281 
speakerMood()282 int Question::speakerMood() {
283 	return _mood & 0xF;
284 }
285 
balloonWinding()286 int Question::balloonWinding() {
287 	return _mood & 0x10;
288 }
289 
290 
Instruction()291 Instruction::Instruction() {
292 	_index = 0;
293 	_flags = 0;
294 
295 	// common
296 	_immediate = 0;
297 	_endif = 0;
298 
299 	// BRA specific
300 	_y = 0;
301 }
302 
getValue()303 int16 ScriptVar::getValue() {
304 
305 	if (_flags & kParaImmediate) {
306 		return _value;
307 	}
308 
309 	if (_flags & kParaLocal) {
310 		return _local->getValue();
311 	}
312 
313 	if (_flags & kParaField) {
314 		return _field->getValue();
315 	}
316 
317 	if (_flags & kParaRandom) {
318 		return (g_vm->_rnd.getRandomNumber(65536) * _value) >> 16;
319 	}
320 
321 	error("Parameter is not an r-value");
322 	return 0;	// for compilers that don't support NORETURN
323 }
324 
setValue(int16 value)325 void ScriptVar::setValue(int16 value) {
326 	if ((_flags & kParaLValue) == 0) {
327 		error("Only l-value can be set");
328 	}
329 
330 	if (_flags & kParaLocal) {
331 		_local->setValue(value);
332 	}
333 
334 	if (_flags & kParaField) {
335 		_field->setValue(value);
336 	}
337 
338 }
339 
setLocal(LocalVariable * local)340 void ScriptVar::setLocal(LocalVariable *local) {
341 	_local = local;
342 	_flags |= (kParaLocal | kParaLValue);
343 }
344 
setField(Animation * anim,AnimationField::AccessorFunc accessor,AnimationField::MutatorFunc mutator)345 void ScriptVar::setField(Animation *anim, AnimationField::AccessorFunc accessor, AnimationField::MutatorFunc mutator) {
346 	_field = new AnimationField(anim, accessor, mutator);
347 	_flags |= (kParaField | kParaLValue);
348 }
349 
setField(Animation * anim,AnimationField::AccessorFunc accessor)350 void ScriptVar::setField(Animation *anim, AnimationField::AccessorFunc accessor) {
351 	_field = new AnimationField(anim, accessor);
352 	_flags |= kParaField;
353 }
354 
setImmediate(int16 value)355 void ScriptVar::setImmediate(int16 value) {
356 	_value = value;
357 	_flags |= kParaImmediate;
358 }
359 
setRandom(int16 seed)360 void ScriptVar::setRandom(int16 seed) {
361 	_value = seed;
362 	_flags |= kParaRandom;
363 }
364 
365 
ScriptVar()366 ScriptVar::ScriptVar() {
367 	_flags = 0;
368 	_local = 0;
369 	_value = 0;
370 	_field = 0;
371 }
372 
~ScriptVar()373 ScriptVar::~ScriptVar() {
374 	delete _field;
375 }
376 
377 
Table(uint32 size)378 Table::Table(uint32 size) : _size(size), _used(0), _disposeMemory(true) {
379 	_data = (char**)calloc(size, sizeof(char *));
380 }
381 
Table(uint32 size,const char ** data)382 Table::Table(uint32 size, const char **data) : _size(size), _used(size), _disposeMemory(false) {
383 	_data = const_cast<char **>(data);
384 }
385 
~Table()386 Table::~Table() {
387 
388 	if (!_disposeMemory) return;
389 
390 	clear();
391 
392 	free(_data);
393 
394 }
395 
addData(const char * s)396 void Table::addData(const char* s) {
397 
398 	if (!(_used < _size))
399 		error("Table overflow");
400 
401 	char *data = (char *)malloc(strlen(s) + 1);
402 	strcpy(data, s);
403 	_data[_used++] = data;
404 }
405 
lookup(const char * s)406 uint16 Table::lookup(const char* s) {
407 
408 	for (uint16 i = 0; i < _used; i++) {
409 		if (!scumm_stricmp(_data[i], s)) return i + 1;
410 	}
411 
412 	return notFound;
413 }
414 
clear()415 void Table::clear() {
416 	for (uint32 i = 0; i < _used; i++)
417 		free(_data[i]);
418 
419 	_used = 0;
420 }
421 
item(uint index) const422 const char *Table::item(uint index) const {
423 	assert(index < _used);
424 	return _data[index];
425 }
426 
427 
FixedTable(uint32 size,uint32 fixed)428 FixedTable::FixedTable(uint32 size, uint32 fixed) : Table(size), _numFixed(fixed) {
429 }
430 
clear()431 void FixedTable::clear() {
432 	uint32 deleted = 0;
433 	for (uint32 i = _numFixed; i < _used; i++) {
434 		free(_data[i]);
435 		_data[i] = 0;
436 		deleted++;
437 	}
438 
439 	_used -= deleted;
440 }
441 
createTableFromStream(uint32 size,Common::SeekableReadStream * stream)442 Table* createTableFromStream(uint32 size, Common::SeekableReadStream *stream) {
443 	assert(stream);
444 
445 	Table *t = new Table(size);
446 	assert(t);
447 
448 	Script s(stream, false);
449 	s.readLineToken();
450 	while (scumm_stricmp(_tokens[0], "ENDTABLE")) {
451 		t->addData(_tokens[0]);
452 		s.readLineToken();
453 	}
454 	delete stream;
455 	return t;
456 }
457 
458 
459 } // namespace Parallaction
460