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_talk_holder.h"
30 #include "engines/wintermute/base/base_dynamic_buffer.h"
31 #include "engines/wintermute/base/base_engine.h"
32 #include "engines/wintermute/base/base_game.h"
33 #include "engines/wintermute/base/base_sprite.h"
34 #include "engines/wintermute/base/scriptables/script_value.h"
35 #include "engines/wintermute/base/scriptables/script.h"
36 #include "engines/wintermute/base/scriptables/script_stack.h"
37 #include "engines/wintermute/platform_osystem.h"
38 #include "common/str.h"
39 
40 namespace Wintermute {
41 
IMPLEMENT_PERSISTENT(AdTalkHolder,false)42 IMPLEMENT_PERSISTENT(AdTalkHolder, false)
43 
44 //////////////////////////////////////////////////////////////////////////
45 AdTalkHolder::AdTalkHolder(BaseGame *inGame) : AdObject(inGame) {
46 	_sprite = nullptr;
47 }
48 
49 
50 //////////////////////////////////////////////////////////////////////////
~AdTalkHolder()51 AdTalkHolder::~AdTalkHolder() {
52 	delete _sprite;
53 	_sprite = nullptr;
54 
55 	for (uint32 i = 0; i < _talkSprites.size(); i++) {
56 		delete _talkSprites[i];
57 	}
58 	_talkSprites.clear();
59 
60 	for (uint32 i = 0; i < _talkSpritesEx.size(); i++) {
61 		delete _talkSpritesEx[i];
62 	}
63 	_talkSpritesEx.clear();
64 }
65 
66 //////////////////////////////////////////////////////////////////////////
getTalkStance(const char * stance)67 BaseSprite *AdTalkHolder::getTalkStance(const char *stance) {
68 	BaseSprite *ret = nullptr;
69 
70 
71 	// forced stance?
72 	if (_forcedTalkAnimName && !_forcedTalkAnimUsed) {
73 		_forcedTalkAnimUsed = true;
74 		delete _animSprite;
75 		_animSprite = new BaseSprite(_gameRef, this);
76 		if (_animSprite) {
77 			bool res = _animSprite->loadFile(_forcedTalkAnimName);
78 			if (DID_FAIL(res)) {
79 				_gameRef->LOG(res, "AdTalkHolder::GetTalkStance: error loading talk sprite (object:\"%s\" sprite:\"%s\")", getName(), _forcedTalkAnimName);
80 				delete _animSprite;
81 				_animSprite = nullptr;
82 			} else {
83 				return _animSprite;
84 			}
85 		}
86 	}
87 
88 
89 	if (stance != nullptr) {
90 		// search special talk stances
91 		for (uint32 i = 0; i < _talkSpritesEx.size(); i++) {
92 			if (scumm_stricmp(_talkSpritesEx[i]->getName(), stance) == 0) {
93 				ret = _talkSpritesEx[i];
94 				break;
95 			}
96 		}
97 		if (ret == nullptr) {
98 			// serach generic talk stances
99 			for (uint32 i = 0; i < _talkSprites.size(); i++) {
100 				if (scumm_stricmp(_talkSprites[i]->getName(), stance) == 0) {
101 					ret = _talkSprites[i];
102 					break;
103 				}
104 			}
105 		}
106 	}
107 
108 	// not a valid stance? get a random one
109 	if (ret == nullptr) {
110 		if (_talkSprites.size() < 1) {
111 			ret = _sprite;
112 		} else {
113 			// TODO: remember last
114 			int rnd = BaseEngine::instance().randInt(0, _talkSprites.size() - 1);
115 			ret = _talkSprites[rnd];
116 		}
117 	}
118 
119 	return ret;
120 }
121 
122 
123 //////////////////////////////////////////////////////////////////////////
124 // high level scripting interface
125 //////////////////////////////////////////////////////////////////////////
scCallMethod(ScScript * script,ScStack * stack,ScStack * thisStack,const char * name)126 bool AdTalkHolder::scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack, const char *name) {
127 	//////////////////////////////////////////////////////////////////////////
128 	// SetSprite
129 	//////////////////////////////////////////////////////////////////////////
130 	if (strcmp(name, "SetSprite") == 0) {
131 		stack->correctParams(1);
132 
133 		ScValue *val = stack->pop();
134 
135 		bool setCurrent = false;
136 		if (_currentSprite && _currentSprite == _sprite) {
137 			setCurrent = true;
138 		}
139 
140 		delete _sprite;
141 		_sprite = nullptr;
142 
143 		if (val->isNULL()) {
144 			_sprite = nullptr;
145 			if (setCurrent) {
146 				_currentSprite = nullptr;
147 			}
148 			stack->pushBool(true);
149 		} else {
150 			const char *filename = val->getString();
151 			BaseSprite *spr = new BaseSprite(_gameRef, this);
152 			if (!spr || DID_FAIL(spr->loadFile(filename))) {
153 				script->runtimeError("SetSprite method failed for file '%s'", filename);
154 				stack->pushBool(false);
155 			} else {
156 				_sprite = spr;
157 				if (setCurrent) {
158 					_currentSprite = _sprite;
159 				}
160 				stack->pushBool(true);
161 			}
162 		}
163 		return STATUS_OK;
164 	}
165 
166 	//////////////////////////////////////////////////////////////////////////
167 	// GetSprite
168 	//////////////////////////////////////////////////////////////////////////
169 	else if (strcmp(name, "GetSprite") == 0) {
170 		stack->correctParams(0);
171 
172 		if (!_sprite || !_sprite->getFilename()) {
173 			stack->pushNULL();
174 		} else {
175 			stack->pushString(_sprite->getFilename());
176 		}
177 		return STATUS_OK;
178 	}
179 
180 	//////////////////////////////////////////////////////////////////////////
181 	// GetSpriteObject
182 	//////////////////////////////////////////////////////////////////////////
183 	else if (strcmp(name, "GetSpriteObject") == 0) {
184 		stack->correctParams(0);
185 
186 		if (!_sprite) {
187 			stack->pushNULL();
188 		} else {
189 			stack->pushNative(_sprite, true);
190 		}
191 		return STATUS_OK;
192 	}
193 
194 	//////////////////////////////////////////////////////////////////////////
195 	// AddTalkSprite
196 	//////////////////////////////////////////////////////////////////////////
197 	else if (strcmp(name, "AddTalkSprite") == 0) {
198 		stack->correctParams(2);
199 
200 		const char *filename = stack->pop()->getString();
201 		bool ex = stack->pop()->getBool();
202 
203 		BaseSprite *spr = new BaseSprite(_gameRef, this);
204 		if (!spr || DID_FAIL(spr->loadFile(filename))) {
205 			stack->pushBool(false);
206 			script->runtimeError("AddTalkSprite method failed for file '%s'", filename);
207 		} else {
208 			if (ex) {
209 				_talkSpritesEx.add(spr);
210 			} else {
211 				_talkSprites.add(spr);
212 			}
213 			stack->pushBool(true);
214 		}
215 		return STATUS_OK;
216 	}
217 
218 	//////////////////////////////////////////////////////////////////////////
219 	// RemoveTalkSprite
220 	//////////////////////////////////////////////////////////////////////////
221 	else if (strcmp(name, "RemoveTalkSprite") == 0) {
222 		stack->correctParams(2);
223 
224 		const char *filename = stack->pop()->getString();
225 		bool ex = stack->pop()->getBool();
226 
227 		bool setCurrent = false;
228 		bool setTemp2 = false;
229 
230 		if (ex) {
231 			for (uint32 i = 0; i < _talkSpritesEx.size(); i++) {
232 				if (scumm_stricmp(_talkSpritesEx[i]->getFilename(), filename) == 0) {
233 					if (_currentSprite == _talkSpritesEx[i]) {
234 						setCurrent = true;
235 					}
236 					if (_tempSprite2 == _talkSpritesEx[i]) {
237 						setTemp2 = true;
238 					}
239 					delete _talkSpritesEx[i];
240 					_talkSpritesEx.remove_at(i);
241 					break;
242 				}
243 			}
244 		} else {
245 			for (uint32 i = 0; i < _talkSprites.size(); i++) {
246 				if (scumm_stricmp(_talkSprites[i]->getFilename(), filename) == 0) {
247 					if (_currentSprite == _talkSprites[i]) {
248 						setCurrent = true;
249 					}
250 					if (_tempSprite2 == _talkSprites[i]) {
251 						setTemp2 = true;
252 					}
253 					delete _talkSprites[i];
254 					_talkSprites.remove_at(i);
255 					break;
256 				}
257 			}
258 
259 		}
260 
261 		stack->pushBool(true);
262 		if (setCurrent) {
263 			_currentSprite = _sprite;
264 		}
265 		if (setTemp2) {
266 			_tempSprite2 = _sprite;
267 		}
268 
269 		return STATUS_OK;
270 	}
271 
272 	//////////////////////////////////////////////////////////////////////////
273 	// SetTalkSprite
274 	//////////////////////////////////////////////////////////////////////////
275 	else if (strcmp(name, "SetTalkSprite") == 0) {
276 		stack->correctParams(2);
277 
278 		const char *filename = stack->pop()->getString();
279 		bool ex = stack->pop()->getBool();
280 		bool setCurrent = false;
281 		bool setTemp2 = false;
282 
283 		BaseSprite *spr = new BaseSprite(_gameRef, this);
284 		if (!spr || DID_FAIL(spr->loadFile(filename))) {
285 			stack->pushBool(false);
286 			script->runtimeError("SetTalkSprite method failed for file '%s'", filename);
287 		} else {
288 
289 			// delete current
290 			if (ex) {
291 				for (uint32 i = 0; i < _talkSpritesEx.size(); i++) {
292 					if (_talkSpritesEx[i] == _currentSprite) {
293 						setCurrent = true;
294 					}
295 					if (_talkSpritesEx[i] == _tempSprite2) {
296 						setTemp2 = true;
297 					}
298 					delete _talkSpritesEx[i];
299 				}
300 				_talkSpritesEx.clear();
301 			} else {
302 				for (uint32 i = 0; i < _talkSprites.size(); i++) {
303 					if (_talkSprites[i] == _currentSprite) {
304 						setCurrent = true;
305 					}
306 					if (_talkSprites[i] == _tempSprite2) {
307 						setTemp2 = true;
308 					}
309 					delete _talkSprites[i];
310 				}
311 				_talkSprites.clear();
312 			}
313 
314 			// set new
315 			if (ex) {
316 				_talkSpritesEx.add(spr);
317 			} else {
318 				_talkSprites.add(spr);
319 			}
320 			stack->pushBool(true);
321 
322 			if (setCurrent) {
323 				_currentSprite = spr;
324 			}
325 			if (setTemp2) {
326 				_tempSprite2 = spr;
327 			}
328 		}
329 		return STATUS_OK;
330 	} else {
331 		return AdObject::scCallMethod(script, stack, thisStack, name);
332 	}
333 }
334 
335 
336 //////////////////////////////////////////////////////////////////////////
scGetProperty(const Common::String & name)337 ScValue *AdTalkHolder::scGetProperty(const Common::String &name) {
338 	_scValue->setNULL();
339 
340 	//////////////////////////////////////////////////////////////////////////
341 	// Type (RO)
342 	//////////////////////////////////////////////////////////////////////////
343 	if (name == "Type") {
344 		_scValue->setString("talk-holder");
345 		return _scValue;
346 	} else {
347 		return AdObject::scGetProperty(name);
348 	}
349 }
350 
351 
352 //////////////////////////////////////////////////////////////////////////
scSetProperty(const char * name,ScValue * value)353 bool AdTalkHolder::scSetProperty(const char *name, ScValue *value) {
354 	/*
355 	//////////////////////////////////////////////////////////////////////////
356 	// Item
357 	//////////////////////////////////////////////////////////////////////////
358 	if (strcmp(name, "Item")==0) {
359 	    SetItem(value->getString());
360 	    return STATUS_OK;
361 	}
362 
363 	else*/ return AdObject::scSetProperty(name, value);
364 }
365 
366 
367 //////////////////////////////////////////////////////////////////////////
scToString()368 const char *AdTalkHolder::scToString() {
369 	return "[talk-holder object]";
370 }
371 
372 
373 //////////////////////////////////////////////////////////////////////////
saveAsText(BaseDynamicBuffer * buffer,int indent)374 bool AdTalkHolder::saveAsText(BaseDynamicBuffer *buffer, int indent) {
375 	for (uint32 i = 0; i < _talkSprites.size(); i++) {
376 		if (_talkSprites[i]->getFilename()) {
377 			buffer->putTextIndent(indent + 2, "TALK=\"%s\"\n", _talkSprites[i]->getFilename());
378 		}
379 	}
380 
381 	for (uint32 i = 0; i < _talkSpritesEx.size(); i++) {
382 		if (_talkSpritesEx[i]->getFilename()) {
383 			buffer->putTextIndent(indent + 2, "TALK_SPECIAL=\"%s\"\n", _talkSpritesEx[i]->getFilename());
384 		}
385 	}
386 
387 	return STATUS_OK;
388 }
389 
390 
391 //////////////////////////////////////////////////////////////////////////
persist(BasePersistenceManager * persistMgr)392 bool AdTalkHolder::persist(BasePersistenceManager *persistMgr) {
393 	AdObject::persist(persistMgr);
394 
395 	persistMgr->transferPtr(TMEMBER_PTR(_sprite));
396 	_talkSprites.persist(persistMgr);
397 	_talkSpritesEx.persist(persistMgr);
398 
399 	return STATUS_OK;
400 }
401 
402 } // End of namespace Wintermute
403