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 /*
24 * This file is based on WME Lite.
25 * http://dead-code.org/redir.php?target=wmelite
26 * Copyright (c) 2011 Jan Nedoma
27 */
28
29 #include "engines/wintermute/base/base_game.h"
30 #include "engines/wintermute/ad/ad_layer.h"
31 #include "engines/wintermute/ad/ad_scene_node.h"
32 #include "engines/wintermute/base/base_dynamic_buffer.h"
33 #include "engines/wintermute/base/base_file_manager.h"
34 #include "engines/wintermute/base/base_parser.h"
35 #include "engines/wintermute/base/scriptables/script_value.h"
36 #include "engines/wintermute/base/scriptables/script.h"
37 #include "engines/wintermute/base/scriptables/script_stack.h"
38 #include "engines/wintermute/platform_osystem.h"
39 #include "common/str.h"
40
41 namespace Wintermute {
42
IMPLEMENT_PERSISTENT(AdLayer,false)43 IMPLEMENT_PERSISTENT(AdLayer, false)
44
45 //////////////////////////////////////////////////////////////////////////
46 AdLayer::AdLayer(BaseGame *inGame) : BaseObject(inGame) {
47 _main = false;
48 _width = _height = 0;
49 _active = true;
50 _closeUp = false;
51 }
52
53
54 //////////////////////////////////////////////////////////////////////////
~AdLayer()55 AdLayer::~AdLayer() {
56 for (uint32 i = 0; i < _nodes.size(); i++) {
57 delete _nodes[i];
58 }
59 _nodes.clear();
60 }
61
62
63 //////////////////////////////////////////////////////////////////////////
loadFile(const char * filename)64 bool AdLayer::loadFile(const char *filename) {
65 char *buffer = (char *)BaseFileManager::getEngineInstance()->readWholeFile(filename);
66 if (buffer == nullptr) {
67 _gameRef->LOG(0, "AdLayer::LoadFile failed for file '%s'", filename);
68 return STATUS_FAILED;
69 }
70
71 bool ret;
72
73 setFilename(filename);
74
75 if (DID_FAIL(ret = loadBuffer(buffer, true))) {
76 _gameRef->LOG(0, "Error parsing LAYER file '%s'", filename);
77 }
78
79 delete[] buffer;
80
81 return ret;
82 }
83
84
85 TOKEN_DEF_START
TOKEN_DEF(LAYER)86 TOKEN_DEF(LAYER)
87 TOKEN_DEF(TEMPLATE)
88 TOKEN_DEF(NAME)
89 TOKEN_DEF(WIDTH)
90 TOKEN_DEF(HEIGHT)
91 TOKEN_DEF(MAIN)
92 TOKEN_DEF(ENTITY)
93 TOKEN_DEF(REGION)
94 TOKEN_DEF(ACTIVE)
95 TOKEN_DEF(EDITOR_SELECTED)
96 TOKEN_DEF(SCRIPT)
97 TOKEN_DEF(CAPTION)
98 TOKEN_DEF(PROPERTY)
99 TOKEN_DEF(CLOSE_UP)
100 TOKEN_DEF(EDITOR_PROPERTY)
101 TOKEN_DEF_END
102 //////////////////////////////////////////////////////////////////////////
103 bool AdLayer::loadBuffer(char *buffer, bool complete) {
104 TOKEN_TABLE_START(commands)
105 TOKEN_TABLE(LAYER)
106 TOKEN_TABLE(TEMPLATE)
107 TOKEN_TABLE(NAME)
108 TOKEN_TABLE(WIDTH)
109 TOKEN_TABLE(HEIGHT)
110 TOKEN_TABLE(MAIN)
111 TOKEN_TABLE(ENTITY)
112 TOKEN_TABLE(REGION)
113 TOKEN_TABLE(ACTIVE)
114 TOKEN_TABLE(EDITOR_SELECTED)
115 TOKEN_TABLE(SCRIPT)
116 TOKEN_TABLE(CAPTION)
117 TOKEN_TABLE(PROPERTY)
118 TOKEN_TABLE(CLOSE_UP)
119 TOKEN_TABLE(EDITOR_PROPERTY)
120 TOKEN_TABLE_END
121
122 char *params;
123 int cmd;
124 BaseParser parser;
125
126 if (complete) {
127 if (parser.getCommand(&buffer, commands, ¶ms) != TOKEN_LAYER) {
128 _gameRef->LOG(0, "'LAYER' keyword expected.");
129 return STATUS_FAILED;
130 }
131 buffer = params;
132 }
133
134 while ((cmd = parser.getCommand(&buffer, commands, ¶ms)) > 0) {
135 switch (cmd) {
136 case TOKEN_TEMPLATE:
137 if (DID_FAIL(loadFile(params))) {
138 cmd = PARSERR_GENERIC;
139 }
140 break;
141
142 case TOKEN_NAME:
143 setName(params);
144 break;
145
146 case TOKEN_CAPTION:
147 setCaption(params);
148 break;
149
150 case TOKEN_MAIN:
151 parser.scanStr(params, "%b", &_main);
152 break;
153
154 case TOKEN_CLOSE_UP:
155 parser.scanStr(params, "%b", &_closeUp);
156 break;
157
158 case TOKEN_WIDTH:
159 parser.scanStr(params, "%d", &_width);
160 break;
161
162 case TOKEN_HEIGHT:
163 parser.scanStr(params, "%d", &_height);
164 break;
165
166 case TOKEN_ACTIVE:
167 parser.scanStr(params, "%b", &_active);
168 break;
169
170 case TOKEN_REGION: {
171 AdRegion *region = new AdRegion(_gameRef);
172 AdSceneNode *node = new AdSceneNode(_gameRef);
173 if (!region || !node || DID_FAIL(region->loadBuffer(params, false))) {
174 cmd = PARSERR_GENERIC;
175 delete region;
176 delete node;
177 region = nullptr;
178 node = nullptr;
179 } else {
180 node->setRegion(region);
181 _nodes.add(node);
182 }
183 }
184 break;
185
186 case TOKEN_ENTITY: {
187 AdEntity *entity = new AdEntity(_gameRef);
188 AdSceneNode *node = new AdSceneNode(_gameRef);
189 if (entity) {
190 entity->_zoomable = false; // scene entites default to NOT zoom
191 }
192 if (!entity || !node || DID_FAIL(entity->loadBuffer(params, false))) {
193 cmd = PARSERR_GENERIC;
194 delete entity;
195 delete node;
196 entity = nullptr;
197 node = nullptr;
198 } else {
199 node->setEntity(entity);
200 _nodes.add(node);
201 }
202 }
203 break;
204
205 case TOKEN_EDITOR_SELECTED:
206 parser.scanStr(params, "%b", &_editorSelected);
207 break;
208
209 case TOKEN_SCRIPT:
210 addScript(params);
211 break;
212
213 case TOKEN_PROPERTY:
214 parseProperty(params, false);
215 break;
216
217 case TOKEN_EDITOR_PROPERTY:
218 parseEditorProperty(params, false);
219 break;
220
221 default:
222 break;
223 }
224 }
225 if (cmd == PARSERR_TOKENNOTFOUND) {
226 _gameRef->LOG(0, "Syntax error in LAYER definition");
227 return STATUS_FAILED;
228 }
229
230 return STATUS_OK;
231 }
232
233
234 //////////////////////////////////////////////////////////////////////////
235 // high level scripting interface
236 //////////////////////////////////////////////////////////////////////////
scCallMethod(ScScript * script,ScStack * stack,ScStack * thisStack,const char * name)237 bool AdLayer::scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack, const char *name) {
238 //////////////////////////////////////////////////////////////////////////
239 // GetNode
240 //////////////////////////////////////////////////////////////////////////
241 if (strcmp(name, "GetNode") == 0) {
242 stack->correctParams(1);
243 ScValue *val = stack->pop();
244 int node = -1;
245
246 if (val->_type == VAL_INT) {
247 node = val->getInt();
248 } else { // get by name
249 for (uint32 i = 0; i < _nodes.size(); i++) {
250 if ((_nodes[i]->_type == OBJECT_ENTITY && scumm_stricmp(_nodes[i]->_entity->getName(), val->getString()) == 0) ||
251 (_nodes[i]->_type == OBJECT_REGION && scumm_stricmp(_nodes[i]->_region->getName(), val->getString()) == 0)) {
252 node = i;
253 break;
254 }
255 }
256 }
257
258 if (node < 0 || node >= (int32)_nodes.size()) {
259 stack->pushNULL();
260 } else {
261 switch (_nodes[node]->_type) {
262 case OBJECT_ENTITY:
263 stack->pushNative(_nodes[node]->_entity, true);
264 break;
265 case OBJECT_REGION:
266 stack->pushNative(_nodes[node]->_region, true);
267 break;
268 default:
269 stack->pushNULL();
270 }
271 }
272 return STATUS_OK;
273 }
274
275 //////////////////////////////////////////////////////////////////////////
276 // AddRegion / AddEntity
277 //////////////////////////////////////////////////////////////////////////
278 else if (strcmp(name, "AddRegion") == 0 || strcmp(name, "AddEntity") == 0) {
279 stack->correctParams(1);
280 ScValue *val = stack->pop();
281
282 AdSceneNode *node = new AdSceneNode(_gameRef);
283 if (strcmp(name, "AddRegion") == 0) {
284 AdRegion *region = new AdRegion(_gameRef);
285 if (!val->isNULL()) {
286 region->setName(val->getString());
287 }
288 node->setRegion(region);
289 stack->pushNative(region, true);
290 } else {
291 AdEntity *entity = new AdEntity(_gameRef);
292 if (!val->isNULL()) {
293 entity->setName(val->getString());
294 }
295 node->setEntity(entity);
296 stack->pushNative(entity, true);
297 }
298 _nodes.add(node);
299 return STATUS_OK;
300 }
301
302 //////////////////////////////////////////////////////////////////////////
303 // InsertRegion / InsertEntity
304 //////////////////////////////////////////////////////////////////////////
305 else if (strcmp(name, "InsertRegion") == 0 || strcmp(name, "InsertEntity") == 0) {
306 stack->correctParams(2);
307 int index = stack->pop()->getInt();
308 ScValue *val = stack->pop();
309
310 AdSceneNode *node = new AdSceneNode(_gameRef);
311 if (strcmp(name, "InsertRegion") == 0) {
312 AdRegion *region = new AdRegion(_gameRef);
313 if (!val->isNULL()) {
314 region->setName(val->getString());
315 }
316 node->setRegion(region);
317 stack->pushNative(region, true);
318 } else {
319 AdEntity *entity = new AdEntity(_gameRef);
320 if (!val->isNULL()) {
321 entity->setName(val->getString());
322 }
323 node->setEntity(entity);
324 stack->pushNative(entity, true);
325 }
326 if (index < 0) {
327 index = 0;
328 }
329 if (index <= (int32)_nodes.size() - 1) {
330 _nodes.insert_at(index, node);
331 } else {
332 _nodes.add(node);
333 }
334
335 return STATUS_OK;
336 }
337
338 //////////////////////////////////////////////////////////////////////////
339 // DeleteNode
340 //////////////////////////////////////////////////////////////////////////
341 else if (strcmp(name, "DeleteNode") == 0) {
342 stack->correctParams(1);
343 ScValue *val = stack->pop();
344
345 AdSceneNode *toDelete = nullptr;
346 if (val->isNative()) {
347 BaseScriptable *temp = val->getNative();
348 for (uint32 i = 0; i < _nodes.size(); i++) {
349 if (_nodes[i]->_region == temp || _nodes[i]->_entity == temp) {
350 toDelete = _nodes[i];
351 break;
352 }
353 }
354 } else {
355 int index = val->getInt();
356 if (index >= 0 && index < (int32)_nodes.size()) {
357 toDelete = _nodes[index];
358 }
359 }
360 if (toDelete == nullptr) {
361 stack->pushBool(false);
362 return STATUS_OK;
363 }
364
365 for (uint32 i = 0; i < _nodes.size(); i++) {
366 if (_nodes[i] == toDelete) {
367 delete _nodes[i];
368 _nodes[i] = nullptr;
369 _nodes.remove_at(i);
370 break;
371 }
372 }
373 stack->pushBool(true);
374 return STATUS_OK;
375 } else {
376 return BaseObject::scCallMethod(script, stack, thisStack, name);
377 }
378 }
379
380
381 //////////////////////////////////////////////////////////////////////////
scGetProperty(const Common::String & name)382 ScValue *AdLayer::scGetProperty(const Common::String &name) {
383 _scValue->setNULL();
384
385 //////////////////////////////////////////////////////////////////////////
386 // Type
387 //////////////////////////////////////////////////////////////////////////
388 if (name == "Type") {
389 _scValue->setString("layer");
390 return _scValue;
391 }
392
393 //////////////////////////////////////////////////////////////////////////
394 // NumNodes (RO)
395 //////////////////////////////////////////////////////////////////////////
396 else if (name == "NumNodes") {
397 _scValue->setInt(_nodes.size());
398 return _scValue;
399 }
400
401 //////////////////////////////////////////////////////////////////////////
402 // Width
403 //////////////////////////////////////////////////////////////////////////
404 else if (name == "Width") {
405 _scValue->setInt(_width);
406 return _scValue;
407 }
408
409 //////////////////////////////////////////////////////////////////////////
410 // Height
411 //////////////////////////////////////////////////////////////////////////
412 else if (name == "Height") {
413 _scValue->setInt(_height);
414 return _scValue;
415 }
416
417 //////////////////////////////////////////////////////////////////////////
418 // Main (RO)
419 //////////////////////////////////////////////////////////////////////////
420 else if (name == "Main") {
421 _scValue->setBool(_main);
422 return _scValue;
423 }
424
425 //////////////////////////////////////////////////////////////////////////
426 // CloseUp
427 //////////////////////////////////////////////////////////////////////////
428 else if (name == "CloseUp") {
429 _scValue->setBool(_closeUp);
430 return _scValue;
431 }
432
433 //////////////////////////////////////////////////////////////////////////
434 // Active
435 //////////////////////////////////////////////////////////////////////////
436 else if (name == "Active") {
437 _scValue->setBool(_active);
438 return _scValue;
439 } else {
440 return BaseObject::scGetProperty(name);
441 }
442 }
443
444
445 //////////////////////////////////////////////////////////////////////////
scSetProperty(const char * name,ScValue * value)446 bool AdLayer::scSetProperty(const char *name, ScValue *value) {
447 //////////////////////////////////////////////////////////////////////////
448 // Name
449 //////////////////////////////////////////////////////////////////////////
450 if (strcmp(name, "Name") == 0) {
451 setName(value->getString());
452 return STATUS_OK;
453 }
454
455 //////////////////////////////////////////////////////////////////////////
456 // CloseUp
457 //////////////////////////////////////////////////////////////////////////
458 else if (strcmp(name, "CloseUp") == 0) {
459 _closeUp = value->getBool();
460 return STATUS_OK;
461 }
462
463 //////////////////////////////////////////////////////////////////////////
464 // Width
465 //////////////////////////////////////////////////////////////////////////
466 else if (strcmp(name, "Width") == 0) {
467 _width = value->getInt();
468 if (_width < 0) {
469 _width = 0;
470 }
471 return STATUS_OK;
472 }
473
474 //////////////////////////////////////////////////////////////////////////
475 // Height
476 //////////////////////////////////////////////////////////////////////////
477 else if (strcmp(name, "Height") == 0) {
478 _height = value->getInt();
479 if (_height < 0) {
480 _height = 0;
481 }
482 return STATUS_OK;
483 }
484
485 //////////////////////////////////////////////////////////////////////////
486 // Active
487 //////////////////////////////////////////////////////////////////////////
488 else if (strcmp(name, "Active") == 0) {
489 bool b = value->getBool();
490 if (b == false && _main) {
491 _gameRef->LOG(0, "Warning: cannot deactivate scene's main layer");
492 } else {
493 _active = b;
494 }
495 return STATUS_OK;
496 } else {
497 return BaseObject::scSetProperty(name, value);
498 }
499 }
500
501
502 //////////////////////////////////////////////////////////////////////////
scToString()503 const char *AdLayer::scToString() {
504 return "[layer]";
505 }
506
507
508 //////////////////////////////////////////////////////////////////////////
saveAsText(BaseDynamicBuffer * buffer,int indent)509 bool AdLayer::saveAsText(BaseDynamicBuffer *buffer, int indent) {
510 buffer->putTextIndent(indent, "LAYER {\n");
511 buffer->putTextIndent(indent + 2, "NAME=\"%s\"\n", getName());
512 buffer->putTextIndent(indent + 2, "CAPTION=\"%s\"\n", getCaption());
513 buffer->putTextIndent(indent + 2, "MAIN=%s\n", _main ? "TRUE" : "FALSE");
514 buffer->putTextIndent(indent + 2, "WIDTH=%d\n", _width);
515 buffer->putTextIndent(indent + 2, "HEIGHT=%d\n", _height);
516 buffer->putTextIndent(indent + 2, "ACTIVE=%s\n", _active ? "TRUE" : "FALSE");
517 buffer->putTextIndent(indent + 2, "EDITOR_SELECTED=%s\n", _editorSelected ? "TRUE" : "FALSE");
518 if (_closeUp) {
519 buffer->putTextIndent(indent + 2, "CLOSE_UP=%s\n", _closeUp ? "TRUE" : "FALSE");
520 }
521
522 for (uint32 i = 0; i < _scripts.size(); i++) {
523 buffer->putTextIndent(indent + 2, "SCRIPT=\"%s\"\n", _scripts[i]->_filename);
524 }
525
526 if (_scProp) {
527 _scProp->saveAsText(buffer, indent + 2);
528 }
529
530 for (uint32 i = 0; i < _nodes.size(); i++) {
531 switch (_nodes[i]->_type) {
532 case OBJECT_ENTITY:
533 _nodes[i]->_entity->saveAsText(buffer, indent + 2);
534 break;
535 case OBJECT_REGION:
536 _nodes[i]->_region->saveAsText(buffer, indent + 2);
537 break;
538 default:
539 error("AdLayer::SaveAsText - Unhandled enum");
540 break;
541 }
542 }
543
544 BaseClass::saveAsText(buffer, indent + 2);
545
546 buffer->putTextIndent(indent, "}\n\n");
547
548 return STATUS_OK;
549 }
550
551
552 //////////////////////////////////////////////////////////////////////////
persist(BasePersistenceManager * persistMgr)553 bool AdLayer::persist(BasePersistenceManager *persistMgr) {
554
555 BaseObject::persist(persistMgr);
556
557 persistMgr->transferBool(TMEMBER(_active));
558 persistMgr->transferBool(TMEMBER(_closeUp));
559 persistMgr->transferSint32(TMEMBER(_height));
560 persistMgr->transferBool(TMEMBER(_main));
561 _nodes.persist(persistMgr);
562 persistMgr->transferSint32(TMEMBER(_width));
563
564 return STATUS_OK;
565 }
566
567 } // End of namespace Wintermute
568