1 /***************************************************************************
2  *   Copyright (C) 2005-2019 by the FIFE team                              *
3  *   http://www.fifengine.net                                              *
4  *   This file is part of FIFE.                                            *
5  *                                                                         *
6  *   FIFE is free software; you can redistribute it and/or                 *
7  *   modify it under the terms of the GNU Lesser General Public            *
8  *   License as published by the Free Software Foundation; either          *
9  *   version 2.1 of the License, or (at your option) any later version.    *
10  *                                                                         *
11  *   This library is distributed in the hope that it will be useful,       *
12  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
13  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
14  *   Lesser General Public License for more details.                       *
15  *                                                                         *
16  *   You should have received a copy of the GNU Lesser General Public      *
17  *   License along with this library; if not, write to the                 *
18  *   Free Software Foundation, Inc.,                                       *
19  *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA          *
20  ***************************************************************************/
21 
22 // Standard C++ library includes
23 #include <iostream>
24 
25 // 3rd party library includes
26 //#include <SDL.h>
27 
28 // FIFE includes
29 // These includes are split up in two parts, separated by one empty line
30 // First block: files included from the FIFE root src directory
31 // Second block: files included from the same folder
32 #include "audio/soundsource.h"
33 #include "util/log/logger.h"
34 #include "util/base/exception.h"
35 #include "util/math/fife_math.h"
36 #include "util/time/timemanager.h"
37 #include "model/metamodel/grids/cellgrid.h"
38 #include "model/metamodel/ipather.h"
39 #include "model/metamodel/action.h"
40 #include "model/metamodel/timeprovider.h"
41 #include "model/structures/layer.h"
42 #include "model/structures/map.h"
43 #include "model/structures/instancetree.h"
44 #include "view/visual.h"
45 #include "pathfinder/route.h"
46 
47 #include "instance.h"
48 
49 namespace FIFE {
50 	static Logger _log(LM_INSTANCE);
51 
52 	class ActionInfo {
53 	public:
ActionInfo(IPather * pather,const Location & curloc)54 		ActionInfo(IPather* pather, const Location& curloc):
55 			m_action(NULL),
56 			m_target(NULL),
57 			m_speed(0),
58 			m_repeating(false),
59 			m_action_start_time(0),
60 			m_action_offset_time(0),
61 			m_prev_call_time(0),
62 			m_pather(pather),
63 			m_leader(NULL),
64 			m_route(NULL),
65 			m_delete_route(true) {}
66 
~ActionInfo()67 		~ActionInfo() {
68 			if (m_route && m_delete_route) {
69 				int32_t sessionId = m_route->getSessionId();
70 				if (sessionId != -1) {
71 					m_pather->cancelSession(sessionId);
72 				}
73 				delete m_route;
74 			}
75 			delete m_target;
76 		}
77 
78 		// Current action, owned by object
79 		Action* m_action;
80 		// target location for ongoing movement
81 		Location* m_target;
82 		// current movement speed
83 		double m_speed;
84 		// should action be repeated? used only for non-moving actions, moving ones repeat until movement is finished
85 		bool m_repeating;
86 		// action start time (ticks)
87 		uint32_t m_action_start_time;
88 		// action offset time (ticks) for resuming an action
89 		uint32_t m_action_offset_time;
90 		// ticks since last call
91 		uint32_t m_prev_call_time;
92 		// pather
93 		IPather* m_pather;
94 		// leader for follow activity
95 		Instance* m_leader;
96 		// pointer to route that contain path and additional information
97 		Route* m_route;
98 		bool m_delete_route;
99 	};
100 
101 	class SayInfo {
102 	public:
SayInfo(const std::string & txt,uint32_t duration)103 		SayInfo(const std::string& txt, uint32_t duration):
104 			m_txt(txt),
105 			m_duration(duration),
106 			m_start_time(0) {}
107 
108 		std::string m_txt;
109 		uint32_t m_duration;
110 		uint32_t m_start_time;
111 	};
112 
InstanceActivity(Instance & source)113 	Instance::InstanceActivity::InstanceActivity(Instance& source):
114 		m_location(source.m_location),
115 		m_oldLocation(source.m_location),
116 		m_rotation(source.m_rotation),
117 		m_oldRotation(source.m_rotation),
118 		m_action(NULL),
119 		m_soundSource(NULL),
120 		m_speed(0),
121 		m_timeMultiplier(1.0),
122 		m_sayText(""),
123  		m_changeListeners(),
124 		m_actionListeners(),
125 		m_actionInfo(NULL),
126 		m_sayInfo(NULL),
127 		m_timeProvider(NULL),
128 		m_blocking(source.m_blocking),
129 		m_additional(ICHANGE_NO_CHANGES) {
130 	}
131 
~InstanceActivity()132 	Instance::InstanceActivity::~InstanceActivity() {
133 		delete m_actionInfo;
134 		delete m_sayInfo;
135 		delete m_timeProvider;
136 		delete m_soundSource;
137 	}
138 
update(Instance & source)139 	void Instance::InstanceActivity::update(Instance& source) {
140 		source.m_changeInfo = ICHANGE_NO_CHANGES;
141 		if (m_additional != ICHANGE_NO_CHANGES) {
142 			source.m_changeInfo = m_additional;
143 			m_additional = ICHANGE_NO_CHANGES;
144 		}
145 		if (m_location != source.m_location) {
146 			source.m_changeInfo |= ICHANGE_LOC;
147 			if (m_location.getLayerCoordinates() != source.m_location.getLayerCoordinates()) {
148 				m_oldLocation.setLayer(m_location.getLayer());
149 				m_oldLocation.setLayerCoordinates(m_location.getLayerCoordinates());
150 				source.m_changeInfo |= ICHANGE_CELL;
151 			}
152 			m_location = source.m_location;
153 		}
154 		if (m_rotation != source.m_rotation) {
155 			m_oldRotation = m_rotation;
156 			source.m_changeInfo |= ICHANGE_ROTATION;
157 			m_rotation = source.m_rotation;
158 		}
159 		if (m_actionInfo && (m_speed != m_actionInfo->m_speed)) {
160 			source.m_changeInfo |= ICHANGE_SPEED;
161 			m_speed = m_actionInfo->m_speed;
162 		}
163 		if (m_actionInfo && (m_action != m_actionInfo->m_action)) {
164 			source.m_changeInfo |= ICHANGE_ACTION;
165 			m_action = m_actionInfo->m_action;
166 		}
167 		if (m_timeProvider && (m_timeMultiplier != m_timeProvider->getMultiplier())) {
168 			source.m_changeInfo |= ICHANGE_TIME_MULTIPLIER;
169 			m_timeMultiplier = m_timeProvider->getMultiplier();
170 		}
171 		if (m_sayInfo && (m_sayText != m_sayInfo->m_txt)) {
172 			source.m_changeInfo |= ICHANGE_SAYTEXT;
173 			m_sayText = m_sayInfo->m_txt;
174 		}
175 		if (m_blocking != source.m_blocking) {
176 			source.m_changeInfo |= ICHANGE_BLOCK;
177 			m_blocking = source.m_blocking;
178 		}
179 
180 		if (source.m_changeInfo != ICHANGE_NO_CHANGES) {
181 			std::vector<InstanceChangeListener*>::iterator i = m_changeListeners.begin();
182 			while (i != m_changeListeners.end()) {
183 				if (NULL != *i)
184 				{
185 					(*i)->onInstanceChanged(&source, source.m_changeInfo);
186 				}
187 				++i;
188 			}
189 			// Really remove "removed" listeners.
190 			m_changeListeners.erase(
191 				std::remove(m_changeListeners.begin(),m_changeListeners.end(),
192 					(InstanceChangeListener*)NULL),
193 				m_changeListeners.end());
194 		}
195 	}
196 
Instance(Object * object,const Location & location,const std::string & identifier)197 	Instance::Instance(Object* object, const Location& location, const std::string& identifier):
198 		m_id(identifier),
199 		m_rotation(0),
200 		m_activity(NULL),
201 		m_changeInfo(ICHANGE_NO_CHANGES),
202 		m_object(object),
203 		m_ownObject(false),
204 		m_location(location),
205 		m_visual(NULL),
206 		m_blocking(object->isBlocking()),
207 		m_overrideBlocking(false),
208 		m_cellStackPos(object->getCellStackPosition()),
209 		m_specialCost(object->isSpecialCost()),
210 		m_cost(object->getCost()),
211 		m_costId(object->getCostId()),
212 		m_mainMultiInstance(NULL) {
213 		// create multi object instances
214 		if (object->isMultiObject()) {
215 			m_mainMultiInstance = this;
216 			uint32_t count = 0;
217 			Layer* layer = m_location.getLayer();
218 			const ExactModelCoordinate& emc = m_location.getExactLayerCoordinatesRef();
219 			const std::set<Object*>& multis = object->getMultiParts();
220 			std::set<Object*>::const_iterator it = multis.begin();
221 			for (; it != multis.end(); ++it, ++count) {
222 				if (*it == m_object) {
223 					continue;
224 				}
225 				std::vector<ModelCoordinate> partcoords = (*it)->getMultiPartCoordinates(m_rotation);
226 				std::vector<ModelCoordinate>::iterator coordit = partcoords.begin();
227 				for (; coordit != partcoords.end(); ++coordit) {
228 					ExactModelCoordinate tmp_emc(emc.x+(*coordit).x, emc.y+(*coordit).y, emc.z+(*coordit).z);
229 					std::ostringstream counter;
230 					counter << count;
231 					Instance* instance = layer->createInstance(*it, tmp_emc, identifier+counter.str());
232 					InstanceVisual::create(instance);
233 					m_multiInstances.push_back(instance);
234 					instance->addDeleteListener(this);
235 					instance->setMainMultiInstance(this);
236 				}
237 			}
238 		}
239 	}
240 
~Instance()241 	Instance::~Instance() {
242 		std::vector<InstanceDeleteListener *>::iterator itor;
243 		for(itor = m_deleteListeners.begin(); itor != m_deleteListeners.end(); ++itor) {
244 			if (*itor != NULL) {
245 				(*itor)->onInstanceDeleted(this);
246 			}
247 		}
248 
249 		if(m_activity && m_activity->m_actionInfo) {
250 			// Don't ditribute onActionFinished in case we're already
251 			// deleting.
252 			m_activity->m_actionListeners.clear();
253 			finalizeAction();
254 		}
255 
256 		if (!m_multiInstances.empty()) {
257 			std::vector<Instance*>::iterator it = m_multiInstances.begin();
258 			for (; it != m_multiInstances.end(); ++it) {
259 				(*it)->removeDeleteListener(this);
260 				(*it)->setMainMultiInstance(NULL);
261 			}
262 		}
263 
264 		delete m_activity;
265 		delete m_visual;
266 		if (m_ownObject) {
267 			delete m_object;
268 		}
269 	}
270 
initializeChanges()271 	void Instance::initializeChanges() {
272 		if (!m_activity) {
273 			m_activity = new InstanceActivity(*this);
274 		}
275 		if (m_location.getLayer()) {
276 			m_location.getLayer()->setInstanceActivityStatus(this, true);
277 		}
278 	}
279 
prepareForUpdate()280 	void Instance::prepareForUpdate() {
281 		if (isActive()) {
282 			refresh();
283 		} else {
284 			initializeChanges();
285 		}
286 	}
287 
isActive() const288 	bool Instance::isActive() const {
289 		return (m_activity != 0);
290 	}
291 
getObject()292 	Object* Instance::getObject() {
293 		return m_object;
294 	}
295 
setLocation(const Location & loc)296 	void Instance::setLocation(const Location& loc) {
297 		// ToDo: Handle the case when the layers are different
298 		if(m_location != loc) {
299 			prepareForUpdate();
300 
301 			if (m_location.getLayerCoordinates() != loc.getLayerCoordinates()) {
302 				m_location.getLayer()->getInstanceTree()->removeInstance(this);
303 				m_location = loc;
304 				m_location.getLayer()->getInstanceTree()->addInstance(this);
305 			} else {
306 				m_location = loc;
307 			}
308 		}
309 	}
310 
getLocation() const311 	Location Instance::getLocation() const {
312 		return m_location;
313 	}
314 
getLocationRef()315 	Location& Instance::getLocationRef() {
316 		return m_location;
317 	}
318 
setRotation(int32_t rotation)319 	void Instance::setRotation(int32_t rotation) {
320 		while (rotation < 0) {
321 			rotation += 360;
322 		}
323 		rotation %= 360;
324 		if(m_rotation != rotation) {
325 			prepareForUpdate();
326 			m_rotation = rotation;
327 		}
328 	}
329 
getRotation() const330 	int32_t Instance::getRotation() const {
331 		return m_rotation;
332 	}
333 
setId(const std::string & identifier)334 	void Instance::setId(const std::string& identifier) {
335 		m_id = identifier;
336 	}
337 
getId()338 	const std::string& Instance::getId() {
339 		return m_id;
340 	}
341 
setBlocking(bool blocking)342 	void Instance::setBlocking(bool blocking) {
343 		if (m_overrideBlocking) {
344 			prepareForUpdate();
345 			m_blocking = blocking;
346 		}
347 	}
348 
isBlocking() const349 	bool Instance::isBlocking() const {
350 		return m_blocking;
351 	}
352 
setOverrideBlocking(bool overblock)353 	void Instance::setOverrideBlocking(bool overblock) {
354 		m_overrideBlocking = overblock;
355 	}
356 
isOverrideBlocking() const357 	bool Instance::isOverrideBlocking() const {
358 		return m_overrideBlocking;
359 	}
360 
addActionListener(InstanceActionListener * listener)361 	void Instance::addActionListener(InstanceActionListener* listener) {
362 		initializeChanges();
363 		m_activity->m_actionListeners.push_back(listener);
364 	}
365 
removeActionListener(InstanceActionListener * listener)366 	void Instance::removeActionListener(InstanceActionListener* listener) {
367 		if (!m_activity) {
368 			return;
369 		}
370 		std::vector<InstanceActionListener*>::iterator i = m_activity->m_actionListeners.begin();
371 		while (i != m_activity->m_actionListeners.end()) {
372 			if ((*i) == listener) {
373 				*i = NULL;
374 				return;
375 			}
376 			++i;
377 		}
378 		FL_WARN(_log, "Cannot remove unknown listener");
379 	}
380 
addChangeListener(InstanceChangeListener * listener)381 	void Instance::addChangeListener(InstanceChangeListener* listener) {
382 		initializeChanges();
383 		m_activity->m_changeListeners.push_back(listener);
384 	}
385 
callOnActionFrame(Action * action,int32_t frame)386 	void Instance::callOnActionFrame(Action* action, int32_t frame) {
387 		if (!m_activity) {
388 			return;
389 		}
390 
391 		std::vector<InstanceActionListener*>::iterator i = m_activity->m_actionListeners.begin();
392 		while (i != m_activity->m_actionListeners.end()) {
393 			if(*i) {
394 				(*i)->onInstanceActionFrame(this, action, frame);
395 			}
396 			++i;
397 		}
398 	}
399 
removeChangeListener(InstanceChangeListener * listener)400 	void Instance::removeChangeListener(InstanceChangeListener* listener) {
401 		if (!m_activity) {
402 			return;
403 		}
404 		std::vector<InstanceChangeListener*>::iterator i = m_activity->m_changeListeners.begin();
405 		while (i != m_activity->m_changeListeners.end()) {
406 			if ((*i) == listener) {
407 				*i = NULL;
408 				return;
409 			}
410 			++i;
411 		}
412 		FL_WARN(_log, "Cannot remove unknown listener");
413 	}
414 
initializeAction(const std::string & actionName)415 	void Instance::initializeAction(const std::string& actionName) {
416 		assert(m_object);
417 
418 		initializeChanges();
419 		const Action *old_action = m_activity->m_actionInfo ? m_activity->m_actionInfo->m_action : NULL;
420 		if (m_activity->m_actionInfo) {
421 			cancelAction();
422 		}
423 		m_activity->m_actionInfo = new ActionInfo(m_object->getPather(), m_location);
424 		m_activity->m_actionInfo->m_action = m_object->getAction(actionName);
425 		if (!m_activity->m_actionInfo->m_action) {
426 			delete m_activity->m_actionInfo;
427 			m_activity->m_actionInfo = NULL;
428 			throw NotFound(std::string("action ") + actionName + " not found");
429 		}
430 		m_activity->m_actionInfo->m_prev_call_time = getRuntime();
431 		if (m_activity->m_actionInfo->m_action != old_action) {
432 			m_activity->m_actionInfo->m_action_start_time = m_activity->m_actionInfo->m_prev_call_time;
433 	    }
434 		// start sound
435 		if (m_activity->m_actionInfo->m_action->getAudio()) {
436 			if (!m_activity->m_soundSource) {
437 				m_activity->m_soundSource = new SoundSource(this);
438 			}
439 			m_activity->m_soundSource->setActionAudio(m_activity->m_actionInfo->m_action->getAudio());
440 		} else if (old_action && old_action->getAudio()) {
441 			m_activity->m_soundSource->setActionAudio(NULL);
442 		}
443 
444 		if (isMultiObject()) {
445 			std::vector<Instance*>::iterator multi_it = m_multiInstances.begin();
446 			for (; multi_it != m_multiInstances.end(); ++multi_it) {
447 				(*multi_it)->initializeAction(actionName);
448 			}
449 		}
450 	}
451 
move(const std::string & actionName,const Location & target,const double speed,const std::string & costId)452 	void Instance::move(const std::string& actionName, const Location& target, const double speed, const std::string& costId) {
453 		// if new move is identical with the old then return
454 		if (m_activity) {
455 			if (m_activity->m_actionInfo) {
456 				if (m_activity->m_actionInfo->m_target) {
457 					if (m_activity->m_actionInfo->m_target->getLayerCoordinates() == target.getLayerCoordinates() &&
458 						Mathd::Equal(speed, m_activity->m_actionInfo->m_speed) &&
459 						m_activity->m_actionInfo->m_action == m_object->getAction(actionName) &&
460 						costId == m_activity->m_actionInfo->m_route->getCostId()) {
461 
462 						return;
463 					}
464 				}
465 			}
466 		}
467 		initializeAction(actionName);
468 		m_activity->m_actionInfo->m_target = new Location(target);
469 		m_activity->m_actionInfo->m_speed = speed;
470 		FL_DBG(_log, LMsg("starting action ") <<  actionName << " from" << m_location << " to " << target << " with speed " << speed);
471 
472 		Route* route = m_activity->m_actionInfo->m_route;
473 		if (!route) {
474 			route = new Route(m_location, *m_activity->m_actionInfo->m_target);
475 			route->setRotation(getRotation());
476 			if (costId != "") {
477 				route->setCostId(costId);
478 			}
479 			if (isMultiCell()) {
480 				route->setObject(m_object);
481 				route->setOccupiedArea(m_location.getLayer()->getCellGrid()->
482 					toMultiCoordinates(m_location.getLayerCoordinates(), m_object->getMultiObjectCoordinates(m_rotation)));
483 			} else if (m_object->getZStepRange() != -1 || !m_object->getWalkableAreas().empty()) {
484 				route->setObject(m_object);
485 			}
486 			m_activity->m_actionInfo->m_route = route;
487 			if (!m_activity->m_actionInfo->m_pather->solveRoute(route)) {
488 				setFacingLocation(target);
489 				finalizeAction();
490 			}
491 		}
492 	}
493 
follow(const std::string & actionName,Instance * leader,const double speed)494 	void Instance::follow(const std::string& actionName, Instance* leader, const double speed) {
495 		initializeAction(actionName);
496 		m_activity->m_actionInfo->m_target = new Location(leader->getLocationRef());
497 		m_activity->m_actionInfo->m_speed = speed;
498 		m_activity->m_actionInfo->m_leader = leader;
499 		leader->addDeleteListener(this);
500 		FL_DBG(_log, LMsg("starting action ") <<  actionName << " from" << m_location << " to " << *m_activity->m_actionInfo->m_target << " with speed " << speed);
501 	}
502 
follow(const std::string & actionName,Route * route,const double speed)503 	void Instance::follow(const std::string& actionName, Route* route, const double speed) {
504 		initializeAction(actionName);
505 		m_activity->m_actionInfo->m_target = new Location(route->getEndNode());
506 		m_activity->m_actionInfo->m_speed = speed;
507 		m_activity->m_actionInfo->m_route = route;
508 		m_activity->m_actionInfo->m_delete_route = false;
509 		if (isMultiCell()) {
510 			route->setObject(m_object);
511 			route->setOccupiedArea(m_location.getLayer()->getCellGrid()->
512 				toMultiCoordinates(m_location.getLayerCoordinates(), m_object->getMultiObjectCoordinates(m_rotation)));
513 		} else if (m_object->getZStepRange() != -1 || !m_object->getWalkableAreas().empty()) {
514 			route->setObject(m_object);
515 		}
516 		FL_DBG(_log, LMsg("starting action ") <<  actionName << " from" << m_location << " to " << *m_activity->m_actionInfo->m_target << " with speed " << speed);
517 	}
518 
cancelMovement(uint32_t length)519 	void Instance::cancelMovement(uint32_t length) {
520 		if (m_activity) {
521 			ActionInfo* info = m_activity->m_actionInfo;
522 			if (info) {
523 				Route* route = info->m_route;
524 				if (route) {
525 					route->cutPath(length);
526 				}
527 			}
528 		}
529 	}
530 
getRoute()531 	Route* Instance::getRoute() {
532 		if (m_activity) {
533 			ActionInfo* info = m_activity->m_actionInfo;
534 			if (info) {
535 				return info->m_route;
536 			}
537 		}
538 		return NULL;
539 	}
540 
setCellStackPosition(uint8_t stack)541 	void Instance::setCellStackPosition(uint8_t stack) {
542 		m_cellStackPos = stack;
543 	}
544 
getCellStackPosition()545 	uint8_t Instance::getCellStackPosition() {
546 		return m_cellStackPos;
547 	}
548 
isSpecialCost()549 	bool Instance::isSpecialCost() {
550 		return m_specialCost;
551 	}
552 
getMultiInstances()553 	const std::vector<Instance*>& Instance::getMultiInstances() {
554 		return m_multiInstances;
555 	}
556 
setMainMultiInstance(Instance * main)557 	void Instance::setMainMultiInstance(Instance* main) {
558 		m_mainMultiInstance = main;
559 	}
560 
getMainMultiInstance()561 	Instance* Instance::getMainMultiInstance() {
562 		return m_mainMultiInstance;
563 	}
564 
actOnce(const std::string & actionName,const Location & direction)565 	void Instance::actOnce(const std::string& actionName, const Location& direction) {
566 		initializeAction(actionName);
567 		m_activity->m_actionInfo->m_repeating = false;
568 		setFacingLocation(direction);
569 	}
570 
actOnce(const std::string & actionName,int32_t rotation)571 	void Instance::actOnce(const std::string& actionName, int32_t rotation) {
572 		initializeAction(actionName);
573 		m_activity->m_actionInfo->m_repeating = false;
574 		setRotation(rotation);
575 	}
576 
actOnce(const std::string & actionName)577 	void Instance::actOnce(const std::string& actionName) {
578 		initializeAction(actionName);
579 		m_activity->m_actionInfo->m_repeating = false;
580 	}
581 
actRepeat(const std::string & actionName,const Location & direction)582 	void Instance::actRepeat(const std::string& actionName, const Location& direction) {
583 		initializeAction(actionName);
584 		m_activity->m_actionInfo->m_repeating = true;
585 		setFacingLocation(direction);
586 	}
587 
actRepeat(const std::string & actionName,int32_t rotation)588 	void Instance::actRepeat(const std::string& actionName, int32_t rotation) {
589 		initializeAction(actionName);
590 		m_activity->m_actionInfo->m_repeating = true;
591 		setRotation(rotation);
592 	}
593 
actRepeat(const std::string & actionName)594 	void Instance::actRepeat(const std::string& actionName) {
595 		initializeAction(actionName);
596 		m_activity->m_actionInfo->m_repeating = true;
597 	}
598 
say(const std::string & text,uint32_t duration)599 	void Instance::say(const std::string& text, uint32_t duration) {
600 		initializeChanges();
601 		delete m_activity->m_sayInfo;
602 		m_activity->m_sayInfo = NULL;
603 
604 		if (text != "") {
605 			m_activity->m_sayInfo = new SayInfo(text, duration);
606 			m_activity->m_sayInfo->m_start_time = getRuntime();
607 		}
608 	}
609 
getSayText() const610 	const std::string* Instance::getSayText() const {
611 		if (m_activity && m_activity->m_sayInfo) {
612 			return &m_activity->m_sayInfo->m_txt;
613 		}
614 		return NULL;
615 	}
616 
processMovement()617 	bool Instance::processMovement() {
618 		ActionInfo* info = m_activity->m_actionInfo;
619 		Route* route = info->m_route;
620 		Location target;
621 		if (info->m_leader) {
622 			target = info->m_leader->getLocationRef();
623 		} else {
624 			target = *info->m_target;
625 		}
626 		if (!route) {
627 			route = new Route(m_location, *info->m_target);
628 			route->setRotation(getRotation());
629 			info->m_route = route;
630 			if (isMultiCell()) {
631 				route->setObject(m_object);
632 				route->setOccupiedArea(m_location.getLayer()->getCellGrid()->
633 					toMultiCoordinates(m_location.getLayerCoordinates(), m_object->getMultiObjectCoordinates(m_rotation)));
634 			} else if (m_object->getZStepRange() != -1 || !m_object->getWalkableAreas().empty()) {
635 				route->setObject(m_object);
636 			}
637 			if (!info->m_pather->solveRoute(route)) {
638 				setFacingLocation(target);
639 				return true;
640 			}
641 		// update target if needed
642 		} else if (route->getEndNode().getLayerCoordinates() != target.getLayerCoordinates()) {
643 			if (route->isReplanned() || isMultiCell()) {
644 				*info->m_target = route->getEndNode();
645 				route->setReplanned(false);
646 				if (isMultiCell()) {
647 					route->setOccupiedArea(m_location.getLayer()->getCellGrid()->
648 						toMultiCoordinates(m_location.getLayerCoordinates(), m_object->getMultiObjectCoordinates(m_rotation)));
649 				}
650 			} else {
651 				if (route->getPathLength() == 0) {
652 					route->setStartNode(m_location);
653 				} else {
654 					route->setStartNode(route->getCurrentNode());
655 				}
656 				route->setEndNode(target);
657 				if (!info->m_pather->solveRoute(route)) {
658 					setFacingLocation(target);
659 					return true;
660 				}
661 			}
662 		}
663 
664 		if (route->getRouteStatus() == ROUTE_SOLVED) {
665 			// timeslice for this movement
666 			uint32_t timedelta = m_activity->m_timeProvider->getGameTime() - info->m_prev_call_time;
667 			// how far we can travel
668 			double distance_to_travel = (static_cast<double>(timedelta) / 1000.0) * info->m_speed;
669 			// location for this movement
670 			Location nextLocation = m_location;
671 			bool can_follow = info->m_pather->followRoute(m_location, route, distance_to_travel, nextLocation);
672 			if (can_follow) {
673 				setRotation(route->getRotation());
674 				// move to another layer
675 				if (m_location.getLayer() != nextLocation.getLayer()) {
676 					m_location.getLayer()->getMap()->addInstanceForTransfer(this, nextLocation);
677 					if (!m_multiInstances.empty()) {
678 						std::vector<Instance*>::iterator it = m_multiInstances.begin();
679 						for (; it != m_multiInstances.end(); ++it) {
680 							Location newloc = nextLocation;
681 							std::vector<ModelCoordinate> tmpcoords = m_location.getLayer()->getCellGrid()->
682 								toMultiCoordinates(nextLocation.getLayerCoordinates(), (*it)->getObject()->getMultiPartCoordinates(m_rotation));
683 							newloc.setLayerCoordinates(tmpcoords.front());
684 							m_location.getLayer()->getMap()->addInstanceForTransfer(*it, newloc);
685 						}
686 					}
687 					return false;
688 				}
689 				setLocation(nextLocation);
690 				return false;
691 			}
692 			// move to another layer
693 			if (m_location.getLayer() != nextLocation.getLayer()) {
694 				m_location.getLayer()->getMap()->addInstanceForTransfer(this, nextLocation);
695 				if (!m_multiInstances.empty()) {
696 					std::vector<Instance*>::iterator it = m_multiInstances.begin();
697 					for (; it != m_multiInstances.end(); ++it) {
698 						Location newloc = nextLocation;
699 						std::vector<ModelCoordinate> tmpcoords = m_location.getLayer()->getCellGrid()->
700 							toMultiCoordinates(nextLocation.getLayerCoordinates(), (*it)->getObject()->getMultiPartCoordinates(m_rotation));
701 						newloc.setLayerCoordinates(tmpcoords.front());
702 						m_location.getLayer()->getMap()->addInstanceForTransfer(*it, newloc);
703 					}
704 				}
705 				return true;
706 			}
707 			setLocation(nextLocation);
708 			// need new route?
709 			if (route->getEndNode().getLayerCoordinates() != m_location.getLayerCoordinates()) {
710 				if (m_location.getLayerDistanceTo(target) > 1.5) {
711 					if (route->getPathLength() == 0) {
712 						route->setStartNode(m_location);
713 					} else {
714 						route->setStartNode(route->getPreviousNode());
715 					}
716 					route->setEndNode(target);
717 					route->setOccupiedArea(m_location.getLayer()->getCellGrid()->
718 						toMultiCoordinates(m_location.getLayerCoordinates(), m_object->getMultiObjectCoordinates(m_rotation)));
719 					return !info->m_pather->solveRoute(route);
720 				}
721 				setFacingLocation(target);
722 			}
723 			return true;
724 		} else if (route->getRouteStatus() == ROUTE_FAILED) {
725 			return true;
726 		}
727 		return false;
728 	}
729 
update()730 	InstanceChangeInfo Instance::update() {
731 		if (!m_activity) {
732 			return ICHANGE_NO_CHANGES;
733 		}
734 		// remove DeleteListeners
735 		m_deleteListeners.erase(std::remove(m_deleteListeners.begin(),m_deleteListeners.end(),
736 				(InstanceDeleteListener*)NULL),	m_deleteListeners.end());
737 
738 		if (!m_activity->m_timeProvider) {
739 			bindTimeProvider();
740 		}
741 		ActionInfo* info = m_activity->m_actionInfo;
742 		if (info) {
743 //			FL_DBG(_log, "updating instance");
744 
745 			if (info->m_target) {
746 //				FL_DBG(_log, "action contains target for movement");
747 				bool movement_finished = processMovement();
748 				if (movement_finished) {
749 //					FL_DBG(_log, "movement finished");
750 					finalizeAction();
751 				}
752 			} else {
753 //				FL_DBG(_log, "action does not contain target for movement");
754 				if (m_activity->m_timeProvider->getGameTime() - info->m_action_start_time + info->m_action_offset_time >= info->m_action->getDuration()) {
755 					if (info->m_repeating) {
756 						info->m_action_start_time = m_activity->m_timeProvider->getGameTime();
757 						// prock: offset no longer needed
758 						info->m_action_offset_time = 0;
759 					} else if (!m_object->isMultiPart()) {
760 						finalizeAction();
761 					}
762 				}
763 			}
764 
765 			// previous code may invalidate actioninfo.
766 			if( m_activity->m_actionInfo ) {
767 				m_activity->m_actionInfo->m_prev_call_time = m_activity->m_timeProvider->getGameTime();
768 			}
769 		}
770 		m_activity->update(*this);
771 		if (m_activity->m_sayInfo) {
772 			if (m_activity->m_sayInfo->m_duration > 0) {
773 				if (m_activity->m_timeProvider->getGameTime() >= m_activity->m_sayInfo->m_start_time + m_activity->m_sayInfo->m_duration) {
774 					say("");
775 				}
776 			}
777 		} else if (!m_activity->m_actionInfo && m_changeInfo == ICHANGE_NO_CHANGES && m_activity->m_actionListeners.empty() && m_activity->m_changeListeners.empty()) {
778 			// delete superfluous activity
779 			delete m_activity;
780 			m_activity = 0;
781 			return ICHANGE_NO_CHANGES;
782 		}
783 		return m_changeInfo;
784 	}
785 
finalizeAction()786 	void Instance::finalizeAction() {
787 		FL_DBG(_log, "finalizing action");
788 		assert(m_activity);
789 		assert(m_activity->m_actionInfo);
790 
791 		if( m_activity->m_actionInfo->m_leader ) {
792 			m_activity->m_actionInfo->m_leader->removeDeleteListener(this);
793 		}
794 
795 		Action* action = m_activity->m_actionInfo->m_action;
796 		delete m_activity->m_actionInfo;
797 		m_activity->m_actionInfo = NULL;
798 		// this is needed in case the new action is set on the same pump and
799 		// it is the same action as the finalized action
800 		m_activity->m_action = NULL;
801 
802 		// stop audio
803 		if (action->getAudio() && m_activity->m_soundSource) {
804 			m_activity->m_soundSource->setActionAudio(NULL);
805 		}
806 
807 		if (isMultiObject()) {
808 			std::vector<Instance*>::iterator multi_it = m_multiInstances.begin();
809 			for (; multi_it != m_multiInstances.end(); ++multi_it) {
810 				(*multi_it)->finalizeAction();
811 			}
812 		}
813 		std::vector<InstanceActionListener*>::iterator i = m_activity->m_actionListeners.begin();
814 		while (i != m_activity->m_actionListeners.end()) {
815 			if(*i)
816 				(*i)->onInstanceActionFinished(this, action);
817 			++i;
818 		}
819 		m_activity->m_actionListeners.erase(
820 			std::remove(m_activity->m_actionListeners.begin(),
821 				m_activity->m_actionListeners.end(),
822 				(InstanceActionListener*)NULL),
823 			m_activity->m_actionListeners.end());
824 	}
825 
cancelAction()826 	void Instance::cancelAction() {
827 		FL_DBG(_log, "cancel action");
828 		assert(m_activity);
829 		assert(m_activity->m_actionInfo);
830 
831 		if( m_activity->m_actionInfo->m_leader ) {
832 			m_activity->m_actionInfo->m_leader->removeDeleteListener(this);
833 		}
834 
835 		Action* action = m_activity->m_actionInfo->m_action;
836 		delete m_activity->m_actionInfo;
837 		m_activity->m_actionInfo = NULL;
838 		// this is needed in case the new action is set on the same pump and
839 		// it is the same action as the canceled action
840 		m_activity->m_action = NULL;
841 
842 		if (isMultiObject()) {
843 			std::vector<Instance*>::iterator multi_it = m_multiInstances.begin();
844 			for (; multi_it != m_multiInstances.end(); ++multi_it) {
845 				(*multi_it)->cancelAction();
846 			}
847 		}
848 		std::vector<InstanceActionListener*>::iterator i = m_activity->m_actionListeners.begin();
849 		while (i != m_activity->m_actionListeners.end()) {
850 			if(*i)
851 				(*i)->onInstanceActionCancelled(this, action);
852 			++i;
853 		}
854 		m_activity->m_actionListeners.erase(
855 			std::remove(m_activity->m_actionListeners.begin(),
856 				m_activity->m_actionListeners.end(),
857 				(InstanceActionListener*)NULL),
858 			m_activity->m_actionListeners.end());
859 	}
860 
getCurrentAction() const861 	Action* Instance::getCurrentAction() const {
862 		if (m_activity && m_activity->m_actionInfo) {
863 			return m_activity->m_actionInfo->m_action;
864 		}
865 		return NULL;
866 	}
867 
getTargetLocation() const868 	Location Instance::getTargetLocation() const {
869 		if (m_activity && m_activity->m_actionInfo && m_activity->m_actionInfo->m_target) {
870 			return *m_activity->m_actionInfo->m_target;
871 		}
872 		return m_location;
873 	}
874 
getMovementSpeed() const875 	double Instance::getMovementSpeed() const {
876 		if (m_activity && m_activity->m_actionInfo) {
877 			return m_activity->m_actionInfo->m_speed;
878 		}
879 		return 0;
880 	}
881 
setFacingLocation(const Location & loc)882 	void Instance::setFacingLocation(const Location& loc) {
883 		setRotation(getAngleBetween(m_location, loc));
884 	}
885 
getFacingLocation()886 	Location Instance::getFacingLocation() {
887 		return getFacing(m_location, m_rotation);
888 	}
889 
getOldLocationRef()890 	Location& Instance::getOldLocationRef() {
891 		if (m_activity) {
892 			return m_activity->m_oldLocation;
893 		}
894 		return m_location;
895 	}
896 
getOldRotation() const897 	int32_t Instance::getOldRotation() const {
898 		if (m_activity) {
899 			return m_activity->m_oldRotation;
900 		}
901 		return m_rotation;
902 	}
903 
getActionRuntime()904 	uint32_t Instance::getActionRuntime() {
905 		if (m_activity && m_activity->m_actionInfo) {
906 			if(!m_activity->m_timeProvider)
907 				bindTimeProvider();
908 			return m_activity->m_timeProvider->getGameTime() - m_activity->m_actionInfo->m_action_start_time + m_activity->m_actionInfo->m_action_offset_time;
909 		}
910 		return getRuntime();
911 	}
912 
setActionRuntime(uint32_t time_offset)913 	void Instance::setActionRuntime(uint32_t time_offset) {
914 		m_activity->m_actionInfo->m_action_offset_time = time_offset;
915 	}
916 
bindTimeProvider()917 	void Instance::bindTimeProvider() {
918 		float multiplier = 1.0;
919 		if (m_activity->m_timeProvider) {
920 			multiplier = m_activity->m_timeProvider->getMultiplier();
921 		}
922 		delete m_activity->m_timeProvider;
923 		m_activity->m_timeProvider = NULL;
924 
925 		if (m_location.getLayer()) {
926 			Map* map = m_location.getLayer()->getMap();
927 			if (map) {
928 				m_activity->m_timeProvider = new TimeProvider(map->getTimeProvider());
929 			}
930 		}
931 		if (!m_activity->m_timeProvider) {
932 			m_activity->m_timeProvider = new TimeProvider(NULL);
933 		}
934 		m_activity->m_timeProvider->setMultiplier(multiplier);
935 	}
936 
refresh()937 	void Instance::refresh() {
938 		initializeChanges();
939 		bindTimeProvider();
940 	}
941 
getChangeInfo()942 	InstanceChangeInfo Instance::getChangeInfo() {
943 		if (m_activity) {
944 			return m_changeInfo;
945 		}
946 		return ICHANGE_NO_CHANGES;
947 	}
948 
callOnTransparencyChange()949 	void Instance::callOnTransparencyChange() {
950 		prepareForUpdate();
951 		m_activity->m_additional |= ICHANGE_TRANSPARENCY;
952 	}
953 
callOnVisibleChange()954 	void Instance::callOnVisibleChange() {
955 		prepareForUpdate();
956 		m_activity->m_additional |= ICHANGE_VISIBLE;
957 	}
958 
callOnStackPositionChange()959 	void Instance::callOnStackPositionChange() {
960 		prepareForUpdate();
961 		m_activity->m_additional |= ICHANGE_STACKPOS;
962 	}
963 
setTimeMultiplier(float multip)964 	void Instance::setTimeMultiplier(float multip) {
965 		initializeChanges();
966 		if (!m_activity->m_timeProvider) {
967 			bindTimeProvider();
968 		}
969 		m_activity->m_timeProvider->setMultiplier(multip);
970 	}
971 
getTimeMultiplier()972 	float Instance::getTimeMultiplier() {
973 		if (m_activity && m_activity->m_timeProvider) {
974 			return m_activity->m_timeProvider->getMultiplier();
975 		}
976 		return 1.0;
977 	}
978 
getTotalTimeMultiplier()979 	float Instance::getTotalTimeMultiplier() {
980 		if (m_activity && m_activity->m_timeProvider) {
981 			return m_activity->m_timeProvider->getTotalMultiplier();
982 		}
983 		if (m_location.getLayer()) {
984 			Map* map = m_location.getLayer()->getMap();
985 			if (map && map->getTimeProvider()) {
986 				return map->getTimeProvider()->getTotalMultiplier();
987 			}
988 		}
989 		return 1.0;
990 	}
991 
getRuntime()992 	uint32_t Instance::getRuntime() {
993 		if (m_activity) {
994 			if(!m_activity->m_timeProvider)
995 				bindTimeProvider();
996 			return m_activity->m_timeProvider->getGameTime();
997 		}
998 		if (m_location.getLayer()) {
999 			Map* map = m_location.getLayer()->getMap();
1000 			if (map && map->getTimeProvider()) {
1001 				return map->getTimeProvider()->getGameTime();
1002 			}
1003 		}
1004 		return TimeManager::instance()->getTime();
1005 	}
1006 
setCost(const std::string & id,double cost)1007 	void Instance::setCost(const std::string& id, double cost) {
1008 		m_specialCost = true;
1009 		m_costId = id;
1010 		m_cost = cost;
1011 	}
1012 
resetCost()1013 	void Instance::resetCost() {
1014 		m_specialCost = false;
1015 	}
1016 
getCost()1017 	double Instance::getCost() {
1018 		if (m_specialCost) {
1019 			return m_cost;
1020 		}
1021 		return m_object->getCost();
1022 	}
1023 
getCostId()1024 	std::string Instance::getCostId() {
1025 		if (m_specialCost) {
1026 			return m_costId;
1027 		}
1028 		return m_object->getCostId();
1029 	}
1030 
getSpeed()1031 	double Instance::getSpeed() {
1032 		return m_object->getSpeed();
1033 	}
1034 
isSpecialSpeed()1035 	bool Instance::isSpecialSpeed() {
1036 		return m_object->isSpecialSpeed();
1037 	}
1038 
isMultiCell()1039 	bool Instance::isMultiCell() {
1040 		return m_object->isMultiObject();
1041 	}
1042 
isMultiObject()1043 	bool Instance::isMultiObject() {
1044 		return !m_multiInstances.empty();
1045 	}
1046 
updateMultiInstances()1047 	void Instance::updateMultiInstances() {
1048 		if (!m_multiInstances.empty()) {
1049 			// use map coords for rotation and movement
1050 			// instances are changed on InstanceTree but not on CellCache
1051 			Location loc = m_location;
1052 			const ExactModelCoordinate anchor = m_location.getMapCoordinates();
1053 			const ExactModelCoordinate& offset = m_object->getRotationAnchor();
1054 			loc.setExactLayerCoordinates(offset);
1055 			const ExactModelCoordinate anchor_offset = loc.getMapCoordinates();
1056 			int32_t rot = m_rotation;
1057 			if (m_object->isRestrictedRotation()) {
1058 				rot = m_object->getRestrictedRotation(m_rotation);
1059 			}
1060 			double mcos = Mathd::Cos(double(rot) * (Mathd::pi()/180.0));
1061 			double msin = Mathd::Sin(double(rot) * (Mathd::pi()/180.0));
1062 			std::vector<Instance*>::iterator it = m_multiInstances.begin();
1063 			for (; it != m_multiInstances.end(); ++it) {
1064 				// use rotation 0 to get the "default" coordinate
1065 				std::vector<ModelCoordinate> mcv = (*it)->getObject()->getMultiPartCoordinates(0);
1066 				loc.setLayerCoordinates(mcv.front());
1067 				ExactModelCoordinate emc = loc.getMapCoordinates();
1068 				ExactModelCoordinate nemc(emc.x-anchor_offset.x, emc.y-anchor_offset.y);
1069 				emc.x = ((nemc.x * mcos + nemc.y * msin) + anchor_offset.x) + anchor.x;
1070 				emc.y = ((-nemc.x * msin + nemc.y * mcos) + anchor_offset.y) + anchor.y;
1071 				loc.setMapCoordinates(emc);
1072 				(*it)->setLocation(loc);
1073 				(*it)->setRotation(rot);
1074 			}
1075 		}
1076 	}
1077 
addStaticColorOverlay(uint32_t angle,const OverlayColors & colors)1078 	void Instance::addStaticColorOverlay(uint32_t angle, const OverlayColors& colors) {
1079 		if (!m_ownObject) {
1080 			createOwnObject();
1081 		}
1082 		ObjectVisual* objVis = m_object->getVisual<ObjectVisual>();
1083 		objVis->addStaticColorOverlay(angle, colors);
1084 		prepareForUpdate();
1085 		m_activity->m_additional |= ICHANGE_VISUAL;
1086 	}
1087 
getStaticColorOverlay(int32_t angle)1088 	OverlayColors* Instance::getStaticColorOverlay(int32_t angle) {
1089 		if (!m_ownObject) {
1090 			return 0;
1091 		}
1092 		ObjectVisual* objVis = m_object->getVisual<ObjectVisual>();
1093 		return objVis->getStaticColorOverlay(angle);
1094 	}
1095 
removeStaticColorOverlay(int32_t angle)1096 	void Instance::removeStaticColorOverlay(int32_t angle) {
1097 		if (m_ownObject) {
1098 			ObjectVisual* objVis = m_object->getVisual<ObjectVisual>();
1099 			objVis->removeStaticColorOverlay(angle);
1100 			prepareForUpdate();
1101 			m_activity->m_additional |= ICHANGE_VISUAL;
1102 		}
1103 	}
1104 
isStaticColorOverlay()1105 	bool Instance::isStaticColorOverlay() {
1106 		if (!m_ownObject) {
1107 			return false;
1108 		}
1109 		ObjectVisual* objVis = m_object->getVisual<ObjectVisual>();
1110 		return objVis->isColorOverlay();
1111 	}
1112 
addColorOverlay(const std::string & actionName,uint32_t angle,const OverlayColors & colors)1113 	void Instance::addColorOverlay(const std::string& actionName, uint32_t angle, const OverlayColors& colors) {
1114 		ActionVisual* visual = getActionVisual(actionName, true);
1115 		if (visual) {
1116 			visual->addColorOverlay(angle, colors);
1117 			prepareForUpdate();
1118 			m_activity->m_additional |= ICHANGE_VISUAL;
1119 		}
1120 	}
1121 
getColorOverlay(const std::string & actionName,uint32_t angle)1122 	OverlayColors* Instance::getColorOverlay(const std::string& actionName, uint32_t angle) {
1123 		ActionVisual* visual = getActionVisual(actionName, false);
1124 		if (visual) {
1125 			return visual->getColorOverlay(angle);
1126 		}
1127 		return NULL;
1128 	}
1129 
removeColorOverlay(const std::string & actionName,int32_t angle)1130 	void Instance::removeColorOverlay(const std::string& actionName, int32_t angle) {
1131 		ActionVisual* visual = getActionVisual(actionName, false);
1132 		if (visual) {
1133 			visual->removeColorOverlay(angle);
1134 			prepareForUpdate();
1135 			m_activity->m_additional |= ICHANGE_VISUAL;
1136 		}
1137 	}
1138 
addAnimationOverlay(const std::string & actionName,uint32_t angle,int32_t order,const AnimationPtr & animationptr)1139 	void Instance::addAnimationOverlay(const std::string& actionName, uint32_t angle, int32_t order, const AnimationPtr& animationptr) {
1140 		ActionVisual* visual = getActionVisual(actionName, true);
1141 		if (visual) {
1142 			visual->addAnimationOverlay(angle, order, animationptr);
1143 			prepareForUpdate();
1144 			m_activity->m_additional |= ICHANGE_VISUAL;
1145 		}
1146 	}
1147 
getAnimationOverlay(const std::string & actionName,int32_t angle)1148 	std::map<int32_t, AnimationPtr> Instance::getAnimationOverlay(const std::string& actionName, int32_t angle) {
1149 		ActionVisual* visual = getActionVisual(actionName, false);
1150 		if (visual) {
1151 			return visual->getAnimationOverlay(angle);
1152 		}
1153 		return std::map<int32_t, AnimationPtr>();
1154 	}
1155 
removeAnimationOverlay(const std::string & actionName,uint32_t angle,int32_t order)1156 	void Instance::removeAnimationOverlay(const std::string& actionName, uint32_t angle, int32_t order) {
1157 		ActionVisual* visual = getActionVisual(actionName, false);
1158 		if (visual) {
1159 			visual->removeAnimationOverlay(angle, order);
1160 			prepareForUpdate();
1161 			m_activity->m_additional |= ICHANGE_VISUAL;
1162 		}
1163 	}
1164 
addColorOverlay(const std::string & actionName,uint32_t angle,int32_t order,const OverlayColors & colors)1165 	void Instance::addColorOverlay(const std::string& actionName, uint32_t angle, int32_t order, const OverlayColors& colors) {
1166 		ActionVisual* visual = getActionVisual(actionName, true);
1167 		if (visual) {
1168 			visual->addColorOverlay(angle, order, colors);
1169 			prepareForUpdate();
1170 			m_activity->m_additional |= ICHANGE_VISUAL;
1171 		}
1172 	}
1173 
getColorOverlay(const std::string & actionName,uint32_t angle,int32_t order)1174 	OverlayColors* Instance::getColorOverlay(const std::string& actionName, uint32_t angle, int32_t order) {
1175 		ActionVisual* visual = getActionVisual(actionName, false);
1176 		if (visual) {
1177 			return visual->getColorOverlay(angle, order);
1178 		}
1179 		return NULL;
1180 	}
1181 
removeColorOverlay(const std::string & actionName,int32_t angle,int32_t order)1182 	void Instance::removeColorOverlay(const std::string& actionName, int32_t angle, int32_t order) {
1183 		ActionVisual* visual = getActionVisual(actionName, false);
1184 		if (visual) {
1185 			visual->removeColorOverlay(angle, order);
1186 			prepareForUpdate();
1187 			m_activity->m_additional |= ICHANGE_VISUAL;
1188 		}
1189 	}
1190 
isAnimationOverlay(const std::string & actionName)1191 	bool Instance::isAnimationOverlay(const std::string& actionName) {
1192 		ActionVisual* visual = getActionVisual(actionName, false);
1193 		if (visual) {
1194 			return visual->isAnimationOverlay();
1195 		}
1196 		return false;
1197 	}
1198 
isColorOverlay(const std::string & actionName)1199 	bool Instance::isColorOverlay(const std::string& actionName) {
1200 		ActionVisual* visual = getActionVisual(actionName, false);
1201 		if (visual) {
1202 			return visual->isColorOverlay();
1203 		}
1204 		return false;
1205 	}
1206 
convertToOverlays(const std::string & actionName,bool color)1207 	void Instance::convertToOverlays(const std::string& actionName, bool color) {
1208 		ActionVisual* visual = getActionVisual(actionName, true);
1209 		visual->convertToOverlays(color);
1210 	}
1211 
createOwnObject()1212 	void Instance::createOwnObject() {
1213 		if (!m_ownObject) {
1214 			m_ownObject = true;
1215 			ObjectVisual* ov = m_object->getVisual<ObjectVisual>();
1216 			ObjectVisual* nov = 0;
1217 			m_object = new Object(m_object->getId(), m_object->getNamespace(), m_object);
1218 			if (!ov) {
1219 				ObjectVisual::create(m_object);
1220 			} else {
1221 				nov = new ObjectVisual(*ov);
1222 				m_object->adoptVisual(nov);
1223 			}
1224 		}
1225 	}
1226 
getActionVisual(const std::string & actionName,bool create)1227 	ActionVisual* Instance::getActionVisual(const std::string& actionName, bool create) {
1228 		ActionVisual* nav = NULL;
1229 		if (!m_ownObject) {
1230 			createOwnObject();
1231 		}
1232 		Action* action = m_object->getAction(actionName, false);
1233 		if (!action) {
1234 			action = m_object->getAction(actionName);
1235 			if (!action) {
1236 				throw NotFound(std::string("action ") + actionName + " not found");
1237 			} else if (create) {
1238 				// if we change the current action then we have to replace the pointer
1239 				bool replace = getCurrentAction() == action;
1240 				// check if its the default action
1241 				bool defaultAction = m_object->getDefaultAction() == action;
1242 				ActionVisual* av = action->getVisual<ActionVisual>();
1243 				action = m_object->createAction(actionName, defaultAction);
1244 				nav = new ActionVisual(*av);
1245 				action->adoptVisual(nav);
1246 				if (replace) {
1247 					m_activity->m_actionInfo->m_action = action;
1248 				}
1249 			}
1250 		} else {
1251 			nav = action->getVisual<ActionVisual>();
1252 		}
1253 		return nav;
1254 	}
1255 
addDeleteListener(InstanceDeleteListener * listener)1256 	void Instance::addDeleteListener(InstanceDeleteListener *listener) {
1257 		m_deleteListeners.push_back(listener);
1258 	}
1259 
removeDeleteListener(InstanceDeleteListener * listener)1260 	void Instance::removeDeleteListener(InstanceDeleteListener *listener) {
1261 		if (!m_deleteListeners.empty()) {
1262 			std::vector<InstanceDeleteListener*>::iterator itor;
1263 			itor = std::find(m_deleteListeners.begin(), m_deleteListeners.end(), listener);
1264 			if(itor != m_deleteListeners.end()) {
1265 				if ((*itor) == listener) {
1266 					*itor = NULL;
1267 					return;
1268 				}
1269 			} else {
1270 				FL_WARN(_log, "Cannot remove unknown listener");
1271 			}
1272 		}
1273 	}
1274 
onInstanceDeleted(Instance * instance)1275 	void Instance::onInstanceDeleted(Instance* instance) {
1276 		if(m_activity && m_activity->m_actionInfo &&
1277 			m_activity->m_actionInfo->m_leader == instance) {
1278 				m_activity->m_actionInfo->m_leader = NULL;
1279 		}
1280 		if (isMultiObject()) {
1281 			std::vector<Instance*>::iterator multi_it = m_multiInstances.begin();
1282 			for (; multi_it != m_multiInstances.end(); ++multi_it) {
1283 				if (*multi_it == instance) {
1284 					m_multiInstances.erase(multi_it);
1285 					break;
1286 				}
1287 			}
1288 		}
1289 	}
1290 }
1291