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/ad/ad_sprite_set.h"
30 #include "engines/wintermute/ad/ad_talk_node.h"
31 #include "engines/wintermute/base/base_parser.h"
32 #include "engines/wintermute/base/base_dynamic_buffer.h"
33 #include "engines/wintermute/base/base_game.h"
34 #include "engines/wintermute/base/base_sprite.h"
35 #include "engines/wintermute/utils/utils.h"
36 namespace Wintermute {
37 
IMPLEMENT_PERSISTENT(AdTalkNode,false)38 IMPLEMENT_PERSISTENT(AdTalkNode, false)
39 
40 //////////////////////////////////////////////////////////////////////////
41 AdTalkNode::AdTalkNode(BaseGame *inGame) : BaseClass(inGame) {
42 	_sprite = nullptr;
43 	_spriteFilename = nullptr;
44 	_spriteSet = nullptr;
45 	_spriteSetFilename = nullptr;
46 	_comment = nullptr;
47 
48 	_startTime = _endTime = 0;
49 	_playToEnd = false;
50 	_preCache = false;
51 }
52 
53 
54 //////////////////////////////////////////////////////////////////////////
~AdTalkNode()55 AdTalkNode::~AdTalkNode() {
56 	delete[] _spriteFilename;
57 	delete _sprite;
58 	delete[] _spriteSetFilename;
59 	delete _spriteSet;
60 	delete _comment;
61 	_spriteFilename = nullptr;
62 	_sprite = nullptr;
63 	_spriteSetFilename = nullptr;
64 	_spriteSet = nullptr;
65 	_comment = nullptr;
66 }
67 
68 
69 
70 TOKEN_DEF_START
TOKEN_DEF(ACTION)71 TOKEN_DEF(ACTION)
72 TOKEN_DEF(SPRITESET_FILE)
73 TOKEN_DEF(SPRITESET)
74 TOKEN_DEF(SPRITE)
75 TOKEN_DEF(START_TIME)
76 TOKEN_DEF(END_TIME)
77 TOKEN_DEF(COMMENT)
78 TOKEN_DEF(PRECACHE)
79 TOKEN_DEF(EDITOR_PROPERTY)
80 TOKEN_DEF_END
81 //////////////////////////////////////////////////////////////////////////
82 bool AdTalkNode::loadBuffer(char *buffer, bool complete) {
83 	TOKEN_TABLE_START(commands)
84 	TOKEN_TABLE(ACTION)
85 	TOKEN_TABLE(SPRITESET_FILE)
86 	TOKEN_TABLE(SPRITESET)
87 	TOKEN_TABLE(SPRITE)
88 	TOKEN_TABLE(START_TIME)
89 	TOKEN_TABLE(END_TIME)
90 	TOKEN_TABLE(COMMENT)
91 	TOKEN_TABLE(PRECACHE)
92 	TOKEN_TABLE(EDITOR_PROPERTY)
93 	TOKEN_TABLE_END
94 
95 	char *params;
96 	int cmd;
97 	BaseParser parser;
98 
99 	if (complete) {
100 		if (parser.getCommand(&buffer, commands, &params) != TOKEN_ACTION) {
101 			_gameRef->LOG(0, "'ACTION' keyword expected.");
102 			return STATUS_FAILED;
103 		}
104 		buffer = params;
105 	}
106 
107 	_endTime = 0;
108 	_playToEnd = false;
109 	_preCache = false;
110 
111 	while ((cmd = parser.getCommand(&buffer, commands, &params)) > 0) {
112 		switch (cmd) {
113 		case TOKEN_SPRITE:
114 			BaseUtils::setString(&_spriteFilename, params);
115 			break;
116 
117 		case TOKEN_SPRITESET_FILE:
118 			BaseUtils::setString(&_spriteSetFilename, params);
119 			break;
120 
121 		case TOKEN_SPRITESET: {
122 			delete _spriteSet;
123 			_spriteSet = new AdSpriteSet(_gameRef);
124 			if (!_spriteSet || DID_FAIL(_spriteSet->loadBuffer(params, false))) {
125 				delete _spriteSet;
126 				_spriteSet = nullptr;
127 				cmd = PARSERR_GENERIC;
128 			}
129 		}
130 		break;
131 
132 		case TOKEN_START_TIME:
133 			parser.scanStr(params, "%d", &_startTime);
134 			break;
135 
136 		case TOKEN_END_TIME:
137 			parser.scanStr(params, "%d", &_endTime);
138 			break;
139 
140 		case TOKEN_PRECACHE:
141 			parser.scanStr(params, "%b", &_preCache);
142 			break;
143 
144 		case TOKEN_COMMENT:
145 			if (_gameRef->_editorMode) {
146 				BaseUtils::setString(&_comment, params);
147 			}
148 			break;
149 
150 		case TOKEN_EDITOR_PROPERTY:
151 			parseEditorProperty(params, false);
152 			break;
153 		}
154 	}
155 	if (cmd == PARSERR_TOKENNOTFOUND) {
156 		_gameRef->LOG(0, "Syntax error in ACTION definition");
157 		return STATUS_FAILED;
158 	}
159 
160 	if (cmd == PARSERR_GENERIC) {
161 		_gameRef->LOG(0, "Error loading ACTION definition");
162 		return STATUS_FAILED;
163 	}
164 
165 	if (_endTime == 0) {
166 		_playToEnd = true;
167 	} else {
168 		_playToEnd = false;
169 	}
170 
171 	if (_preCache && _spriteFilename) {
172 		delete _sprite;
173 		_sprite = new BaseSprite(_gameRef);
174 		if (!_sprite || DID_FAIL(_sprite->loadFile(_spriteFilename))) {
175 			return STATUS_FAILED;
176 		}
177 	}
178 
179 	if (_preCache && _spriteSetFilename) {
180 		delete _spriteSet;
181 		_spriteSet = new AdSpriteSet(_gameRef);
182 		if (!_spriteSet || DID_FAIL(_spriteSet->loadFile(_spriteSetFilename))) {
183 			return STATUS_FAILED;
184 		}
185 	}
186 
187 	return STATUS_OK;
188 }
189 
190 
191 
192 //////////////////////////////////////////////////////////////////////////
persist(BasePersistenceManager * persistMgr)193 bool AdTalkNode::persist(BasePersistenceManager *persistMgr) {
194 	persistMgr->transferCharPtr(TMEMBER(_comment));
195 	persistMgr->transferUint32(TMEMBER(_startTime));
196 	persistMgr->transferUint32(TMEMBER(_endTime));
197 	persistMgr->transferBool(TMEMBER(_playToEnd));
198 	persistMgr->transferPtr(TMEMBER_PTR(_sprite));
199 	persistMgr->transferCharPtr(TMEMBER(_spriteFilename));
200 	persistMgr->transferPtr(TMEMBER_PTR(_spriteSet));
201 	persistMgr->transferCharPtr(TMEMBER(_spriteSetFilename));
202 
203 	return STATUS_OK;
204 }
205 
206 
207 //////////////////////////////////////////////////////////////////////////
saveAsText(BaseDynamicBuffer * buffer,int indent)208 bool AdTalkNode::saveAsText(BaseDynamicBuffer *buffer, int indent) {
209 	buffer->putTextIndent(indent, "ACTION {\n");
210 	if (_comment) {
211 		buffer->putTextIndent(indent + 2, "COMMENT=\"%s\"\n", _comment);
212 	}
213 	buffer->putTextIndent(indent + 2, "START_TIME=%d\n", _startTime);
214 	if (!_playToEnd) {
215 		buffer->putTextIndent(indent + 2, "END_TIME=%d\n", _endTime);
216 	}
217 	if (_spriteFilename) {
218 		buffer->putTextIndent(indent + 2, "SPRITE=\"%s\"\n", _spriteFilename);
219 	}
220 	if (_spriteSetFilename) {
221 		buffer->putTextIndent(indent + 2, "SPRITESET_FILE=\"%s\"\n", _spriteSetFilename);
222 	} else if (_spriteSet) {
223 		_spriteSet->saveAsText(buffer, indent + 2);
224 	}
225 	if (_preCache) {
226 		buffer->putTextIndent(indent + 2, "PRECACHE=\"%s\"\n", _preCache ? "TRUE" : "FALSE");
227 	}
228 
229 	BaseClass::saveAsText(buffer, indent + 2);
230 
231 	buffer->putTextIndent(indent, "}\n");
232 
233 	return STATUS_OK;
234 }
235 
236 
237 //////////////////////////////////////////////////////////////////////////
loadSprite()238 bool AdTalkNode::loadSprite() {
239 	if (_spriteFilename && !_sprite) {
240 		_sprite = new BaseSprite(_gameRef);
241 		if (!_sprite || DID_FAIL(_sprite->loadFile(_spriteFilename))) {
242 			delete _sprite;
243 			_sprite = nullptr;
244 			return STATUS_FAILED;
245 		} else {
246 			return STATUS_OK;
247 		}
248 	} else if (_spriteSetFilename && !_spriteSet) {
249 		_spriteSet = new AdSpriteSet(_gameRef);
250 		if (!_spriteSet || DID_FAIL(_spriteSet->loadFile(_spriteSetFilename))) {
251 			delete _spriteSet;
252 			_spriteSet = nullptr;
253 			return STATUS_FAILED;
254 		} else {
255 			return STATUS_OK;
256 		}
257 	} else {
258 		return STATUS_OK;
259 	}
260 }
261 
262 
263 //////////////////////////////////////////////////////////////////////////
isInTimeInterval(uint32 time,TDirection dir)264 bool AdTalkNode::isInTimeInterval(uint32 time, TDirection dir) {
265 	if (time >= _startTime) {
266 		if (_playToEnd) {
267 			if ((_spriteFilename && _sprite == nullptr) || (_sprite && _sprite->isFinished() == false)) {
268 				return true;
269 			} else if ((_spriteSetFilename && _spriteSet == nullptr) || (_spriteSet && _spriteSet->getSprite(dir) && _spriteSet->getSprite(dir)->isFinished() == false)) {
270 				return true;
271 			} else {
272 				return false;
273 			}
274 		} else {
275 			return _endTime >= time;
276 		}
277 	} else {
278 		return false;
279 	}
280 }
281 
282 
283 //////////////////////////////////////////////////////////////////////////
getSprite(TDirection dir)284 BaseSprite *AdTalkNode::getSprite(TDirection dir) {
285 	loadSprite();
286 	if (_sprite) {
287 		return _sprite;
288 	} else if (_spriteSet) {
289 		return _spriteSet->getSprite(dir);
290 	} else {
291 		return nullptr;
292 	}
293 }
294 
295 } // End of namespace Wintermute
296