FIFE  2008.0
 All Classes Namespaces Functions Variables Enumerations Enumerator Pages
instance.cpp
1 /***************************************************************************
2  * Copyright (C) 2006-2011 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 "util/log/logger.h"
33 #include "util/base/exception.h"
34 #include "util/math/fife_math.h"
35 #include "util/time/timemanager.h"
36 #include "model/metamodel/grids/cellgrid.h"
37 #include "model/metamodel/ipather.h"
38 #include "model/metamodel/action.h"
39 #include "model/metamodel/timeprovider.h"
40 #include "model/structures/layer.h"
41 #include "model/structures/map.h"
42 #include "model/structures/instancetree.h"
43 
44 #include "instance.h"
45 
46 namespace FIFE {
47  static Logger _log(LM_INSTANCE);
48 
49  class ActionInfo {
50  public:
51  ActionInfo(IPather* pather, const Location& curloc):
52  m_action(NULL),
53  m_target(NULL),
54  m_speed(0),
55  m_repeating(false),
56  m_action_start_time(0),
57  m_action_offset_time(0),
58  m_prev_call_time(0),
59  m_pather_session_id(-1),
60  m_pather(pather),
61  m_leader(NULL) {}
62 
63  ~ActionInfo() {
64  if (m_pather_session_id != -1) {
65  m_pather->cancelSession(m_pather_session_id);
66  }
67  delete m_target;
68  m_target = NULL;
69  }
70 
71  // Current action, owned by object
72  Action* m_action;
73  // target location for ongoing movement
74  Location* m_target;
75  // current movement speed
76  double m_speed;
77  // should action be repeated? used only for non-moving actions, moving ones repeat until movement is finished
78  bool m_repeating;
79  // action start time (ticks)
80  uint32_t m_action_start_time;
81  // action offset time (ticks) for resuming an action
82  uint32_t m_action_offset_time;
83  // ticks since last call
84  uint32_t m_prev_call_time;
85  // session id for pather
86  int32_t m_pather_session_id;
87  // pather
88  IPather* m_pather;
89  // leader for follow activity
90  Instance* m_leader;
91  };
92 
93  class SayInfo {
94  public:
95  SayInfo(const std::string& txt, uint32_t duration):
96  m_txt(txt),
97  m_duration(duration),
98  m_start_time(0) {}
99 
100  std::string m_txt;
101  uint32_t m_duration;
102  uint32_t m_start_time;
103  };
104 
105  Instance::InstanceActivity::InstanceActivity(Instance& source):
106  m_location(source.m_location),
107  m_rotation(source.m_rotation),
108  m_facinglocation(),
109  m_action(),
110  m_speed(0),
111  m_timemultiplier(1.0),
112  m_saytxt(""),
113  m_changelisteners(),
114  m_actionlisteners(),
115  m_actioninfo(NULL),
116  m_sayinfo(NULL),
117  m_timeprovider(NULL),
118  m_blocking(source.m_blocking) {
119  if (source.m_facinglocation) {
120  m_facinglocation = *source.m_facinglocation;
121  }
122  }
123 
124  Instance::InstanceActivity::~InstanceActivity() {
125  delete m_actioninfo;
126  delete m_sayinfo;
127  delete m_timeprovider;
128  }
129 
130  void Instance::InstanceActivity::update(Instance& source) {
131  source.m_changeinfo = ICHANGE_NO_CHANGES;
132  if (m_location != source.m_location) {
133  source.m_changeinfo |= ICHANGE_LOC;
134  if (m_location.getLayerCoordinates() != source.m_location.getLayerCoordinates()) {
135  source.m_changeinfo |= ICHANGE_CELL;
136  }
137  m_location = source.m_location;
138  }
139  if (m_rotation != source.m_rotation) {
140  source.m_changeinfo |= ICHANGE_ROTATION;
141  m_rotation = source.m_rotation;
142  }
143  if (source.m_facinglocation && (m_facinglocation != *source.m_facinglocation)) {
144  source.m_changeinfo |= ICHANGE_FACING_LOC;
145  m_facinglocation = *source.m_facinglocation;
146  }
147  if (m_actioninfo && (m_speed != m_actioninfo->m_speed)) {
148  source.m_changeinfo |= ICHANGE_SPEED;
149  m_speed = m_actioninfo->m_speed;
150  }
151  if (m_actioninfo && (m_action != m_actioninfo->m_action)) {
152  source.m_changeinfo |= ICHANGE_ACTION;
153  m_action = m_actioninfo->m_action;
154  }
155  if (m_timeprovider && (m_timemultiplier != m_timeprovider->getMultiplier())) {
156  source.m_changeinfo |= ICHANGE_TIME_MULTIPLIER;
157  m_timemultiplier = m_timeprovider->getMultiplier();
158  }
159  if (m_sayinfo && (m_saytxt != m_sayinfo->m_txt)) {
160  source.m_changeinfo |= ICHANGE_SAYTEXT;
161  m_saytxt = m_sayinfo->m_txt;
162  }
163  if (m_blocking != source.m_blocking) {
164  source.m_changeinfo |= ICHANGE_BLOCK;
165  m_blocking = source.m_blocking;
166  }
167 
168  if (source.m_changeinfo != ICHANGE_NO_CHANGES) {
169  std::vector<InstanceChangeListener*>::iterator i = m_changelisteners.begin();
170  while (i != m_changelisteners.end()) {
171  if (NULL != *i)
172  {
173  (*i)->onInstanceChanged(&source, source.m_changeinfo);
174  }
175  ++i;
176  }
177  // Really remove "removed" listeners.
178  m_changelisteners.erase(
179  std::remove(m_changelisteners.begin(),m_changelisteners.end(),
180  (InstanceChangeListener*)NULL),
181  m_changelisteners.end());
182  }
183  }
184 
185  Instance::Instance(Object* object, const Location& location, const std::string& identifier):
186  m_id(identifier),
187  m_rotation(0),
188  m_activity(NULL),
189  m_changeinfo(ICHANGE_NO_CHANGES),
190  m_object(object),
191  m_location(location),
192  m_facinglocation(NULL),
193  m_visual(NULL),
194  m_blocking(object->isBlocking()),
195  m_override_blocking(false) {
196  }
197 
199  std::vector<InstanceDeleteListener *>::iterator itor;
200  for(itor = m_deletelisteners.begin(); itor != m_deletelisteners.end(); ++itor) {
201  if (*itor != NULL) {
202  (*itor)->onInstanceDeleted(this);
203  }
204  }
205 
206  if(m_activity && m_activity->m_actioninfo) {
207  // Don't ditribute onActionFinished in case we're already
208  // deleting.
209  m_activity->m_actionlisteners.clear();
210  finalizeAction();
211  }
212 
213  delete m_activity;
214  delete m_facinglocation;
215  delete m_visual;
216  }
217 
218  void Instance::initializeChanges() {
219  if (!m_activity) {
220  m_activity = new InstanceActivity(*this);
221  if(m_location.getLayer()) {
222  m_location.getLayer()->setInstanceActivityStatus(this, true);
223  }
224  }
225  }
226 
227  bool Instance::isActive() const {
228  return (m_activity != 0);
229  }
230 
231  void Instance::setLocation(const Location& loc) {
232  // ToDo: Handle the case when the layers are different
233  if(m_location != loc) {
234  if(isActive()) {
235  if (m_location.getLayerCoordinates() != loc.getLayerCoordinates()) {
236  m_location.getLayer()->getInstanceTree()->removeInstance(this);
237  m_location = loc;
238  m_location.getLayer()->getInstanceTree()->addInstance(this);
239  } else {
240  m_location = loc;
241  }
242  refresh();
243  } else {
244  initializeChanges();
245  if (m_location.getLayerCoordinates() != loc.getLayerCoordinates()) {
246  m_location.getLayer()->getInstanceTree()->removeInstance(this);
247  m_location = loc;
248  m_location.getLayer()->getInstanceTree()->addInstance(this);
249  } else {
250  m_location = loc;
251  }
252  }
253  }
254  }
255 
256  void Instance::setRotation(int32_t rotation) {
257  if(m_rotation != rotation) {
258  if(isActive()) {
259  m_rotation = rotation;
260  refresh();
261  } else {
262  initializeChanges();
263  m_rotation = rotation;
264  }
265  }
266  }
267 
268  void Instance::setId(const std::string& identifier) {
269  m_id = identifier;
270  }
271 
272  void Instance::setBlocking(bool blocking) {
273  if (m_override_blocking) {
274  m_blocking = blocking;
275  }
276  }
277 
278  bool Instance::isBlocking() const {
279  return m_blocking;
280  }
281 
282  void Instance::addActionListener(InstanceActionListener* listener) {
283  initializeChanges();
284  m_activity->m_actionlisteners.push_back(listener);
285  }
286 
287  void Instance::removeActionListener(InstanceActionListener* listener) {
288  if (!m_activity) {
289  return;
290  }
291  std::vector<InstanceActionListener*>::iterator i = m_activity->m_actionlisteners.begin();
292  while (i != m_activity->m_actionlisteners.end()) {
293  if ((*i) == listener) {
294  *i = NULL;
295  return;
296  }
297  ++i;
298  }
299  FL_WARN(_log, "Cannot remove unknown listener");
300  }
301 
302  void Instance::addChangeListener(InstanceChangeListener* listener) {
303  initializeChanges();
304  m_activity->m_changelisteners.push_back(listener);
305  }
306 
307  void Instance::callOnActionFrame(Action* action, int32_t frame) {
308  if (!m_activity) {
309  return;
310  }
311 
312  std::vector<InstanceActionListener*>::iterator i = m_activity->m_actionlisteners.begin();
313  while (i != m_activity->m_actionlisteners.end()) {
314  if(*i) {
315  (*i)->onInstanceActionFrame(this, action, frame);
316  }
317  ++i;
318  }
319  }
320 
321  void Instance::removeChangeListener(InstanceChangeListener* listener) {
322  if (!m_activity) {
323  return;
324  }
325  std::vector<InstanceChangeListener*>::iterator i = m_activity->m_changelisteners.begin();
326  while (i != m_activity->m_changelisteners.end()) {
327  if ((*i) == listener) {
328  *i = NULL;
329  return;
330  }
331  ++i;
332  }
333  FL_WARN(_log, "Cannot remove unknown listener");
334  }
335  void Instance::initializeAction(const std::string& action_name) {
336  assert(m_object);
337  assert(m_activity);
338  const Action *old_action = m_activity->m_actioninfo ? m_activity->m_actioninfo->m_action : NULL;
339  if (m_activity->m_actioninfo) {
340  delete m_activity->m_actioninfo;
341  m_activity->m_actioninfo = NULL;
342  }
343  m_activity->m_actioninfo = new ActionInfo(m_object->getPather(), m_location);
344  m_activity->m_actioninfo->m_action = m_object->getAction(action_name);
345  if (!m_activity->m_actioninfo->m_action) {
346  delete m_activity->m_actioninfo;
347  m_activity->m_actioninfo = NULL;
348  throw NotFound(std::string("action ") + action_name + " not found");
349  }
350  m_activity->m_actioninfo->m_prev_call_time = getRuntime();
351  if (m_activity->m_actioninfo->m_action != old_action) {
352  m_activity->m_actioninfo->m_action_start_time = m_activity->m_actioninfo->m_prev_call_time;
353  }
354  }
355 
356  void Instance::move(const std::string& action_name, const Location& target, const double speed) {
357  initializeChanges();
358  initializeAction(action_name);
359  m_activity->m_actioninfo->m_target = new Location(target);
360  m_activity->m_actioninfo->m_speed = speed;
361  setFacingLocation(target);
362  FL_DBG(_log, LMsg("starting action ") << action_name << " from" << m_location << " to " << target << " with speed " << speed);
363  }
364 
365  void Instance::follow(const std::string& action_name, Instance* leader, const double speed) {
366  initializeChanges();
367  initializeAction(action_name);
368  m_activity->m_actioninfo->m_target = new Location(leader->getLocationRef());
369  m_activity->m_actioninfo->m_speed = speed;
370  m_activity->m_actioninfo->m_leader = leader;
371  leader->addDeleteListener(this);
372  setFacingLocation(*m_activity->m_actioninfo->m_target);
373  FL_DBG(_log, LMsg("starting action ") << action_name << " from" << m_location << " to " << *m_activity->m_actioninfo->m_target << " with speed " << speed);
374  }
375 
376  void Instance::act(const std::string& action_name, const Location& direction, bool repeating) {
377  initializeChanges();
378  initializeAction(action_name);
379  m_activity->m_actioninfo->m_repeating = repeating;
380  setFacingLocation(direction);
381  }
382 
383  void Instance::say(const std::string& text, uint32_t duration) {
384  initializeChanges();
385  delete m_activity->m_sayinfo;
386  m_activity->m_sayinfo = NULL;
387 
388  if (text != "") {
389  m_activity->m_sayinfo = new SayInfo(text, duration);
390  m_activity->m_sayinfo->m_start_time = getRuntime();
391  }
392  }
393 
394  const std::string* Instance::getSayText() const {
395  if (m_activity && m_activity->m_sayinfo) {
396  return &m_activity->m_sayinfo->m_txt;
397  }
398  return NULL;
399  }
400 
401  void Instance::setFacingLocation(const Location& loc) {
402  if (!m_facinglocation) {
403  m_facinglocation = new Location(loc);
404  } else {
405  *m_facinglocation = loc;
406  }
407  }
408 
409  bool Instance::process_movement() {
410 // FL_DBG(_log, "Moving...");
411  ActionInfo* info = m_activity->m_actioninfo;
412  // timeslice for this movement
413  uint32_t timedelta = m_activity->m_timeprovider->getGameTime() - info->m_prev_call_time;
414 // FL_DBG(_log, LMsg("timedelta ") << timedelta << " prevcalltime " << info->m_prev_call_time);
415  // how far we can travel
416  double distance_to_travel = (static_cast<double>(timedelta) / 1000.0) * info->m_speed;
417 // FL_DBG(_log, LMsg("dist ") << distance_to_travel);
418 
419  Location nextLocation = m_location;
420  info->m_pather_session_id = info->m_pather->getNextLocation(
421  this, *info->m_target,
422  distance_to_travel, nextLocation, *m_facinglocation,
423  info->m_pather_session_id);
424  m_location.getLayer()->getInstanceTree()->removeInstance(this);
425  m_location = nextLocation;
426  //ExactModelCoordinate a = nextLocation.getMapCoordinates();
427  //ExactModelCoordinate b = m_actioninfo->m_target->getMapCoordinates();
428  m_location.getLayer()->getInstanceTree()->addInstance(this);
429  // return if we are close enough to target to stop
430  if (info->m_pather_session_id == -1) {
431  return true;
432  }
433  return false;
434  }
435 
436  InstanceChangeInfo Instance::update() {
437  if (!m_activity) {
438  return ICHANGE_NO_CHANGES;
439  }
440  // remove DeleteListeners
441  m_deletelisteners.erase(std::remove(m_deletelisteners.begin(),m_deletelisteners.end(),
442  (InstanceDeleteListener*)NULL), m_deletelisteners.end());
443  m_activity->update(*this);
444  if (!m_activity->m_timeprovider) {
445  bindTimeProvider();
446  }
447  ActionInfo* info = m_activity->m_actioninfo;
448  if (info) {
449 // FL_DBG(_log, "updating instance");
450 
451  if (info->m_target) {
452 // FL_DBG(_log, "action contains target for movement");
453  // update target if needed
454  if (info->m_leader && (info->m_leader->getLocationRef() != *info->m_target)) {
455  *info->m_target = info->m_leader->getLocation();
456  }
457  bool movement_finished = process_movement();
458  if (movement_finished) {
459 // FL_DBG(_log, "movement finished");
460  finalizeAction();
461  }
462  } else {
463 // FL_DBG(_log, "action does not contain target for movement");
464  if (m_activity->m_timeprovider->getGameTime() - info->m_action_start_time + info->m_action_offset_time >= info->m_action->getDuration()) {
465  if (info->m_repeating) {
466  info->m_action_start_time = m_activity->m_timeprovider->getGameTime();
467  // prock: offset no longer needed
468  info->m_action_offset_time = 0;
469  } else {
470  finalizeAction();
471  }
472  }
473  }
474 
475  // previous code may invalidate actioninfo.
476  if( m_activity->m_actioninfo ) {
477  m_activity->m_actioninfo->m_prev_call_time = m_activity->m_timeprovider->getGameTime();
478  }
479  }
480  if (m_activity->m_sayinfo) {
481  if (m_activity->m_sayinfo->m_duration > 0) {
482  if (m_activity->m_timeprovider->getGameTime() >= m_activity->m_sayinfo->m_start_time + m_activity->m_sayinfo->m_duration) {
483  say("");
484  }
485  }
486  } else if (!m_activity->m_actioninfo && m_changeinfo == ICHANGE_NO_CHANGES && m_activity->m_actionlisteners.empty()) {
487  // delete superfluous activity
488  delete m_activity;
489  m_activity = 0;
490  return ICHANGE_NO_CHANGES;
491  }
492  return m_changeinfo;
493  }
494 
495  void Instance::finalizeAction() {
496  FL_DBG(_log, "finalizing action");
497  assert(m_activity);
498  assert(m_activity->m_actioninfo);
499 
500  if( m_activity->m_actioninfo->m_leader ) {
501  m_activity->m_actioninfo->m_leader->removeDeleteListener(this);
502  }
503 
504  Action* action = m_activity->m_actioninfo->m_action;
505  delete m_activity->m_actioninfo;
506  m_activity->m_actioninfo = NULL;
507 
508  std::vector<InstanceActionListener*>::iterator i = m_activity->m_actionlisteners.begin();
509  while (i != m_activity->m_actionlisteners.end()) {
510  if(*i)
511  (*i)->onInstanceActionFinished(this, action);
512  ++i;
513  }
514  m_activity->m_actionlisteners.erase(
515  std::remove(m_activity->m_actionlisteners.begin(),
516  m_activity->m_actionlisteners.end(),
517  (InstanceActionListener*)NULL),
518  m_activity->m_actionlisteners.end());
519  }
520 
521  Action* Instance::getCurrentAction() const {
522  if (m_activity && m_activity->m_actioninfo) {
523  return m_activity->m_actioninfo->m_action;
524  }
525  return NULL;
526  }
527 
528  Location Instance::getTargetLocation() const {
529  if (m_activity && m_activity->m_actioninfo && m_activity->m_actioninfo->m_target) {
530  return *m_activity->m_actioninfo->m_target;
531  }
532  return m_location;
533  }
534 
535  double Instance::getMovementSpeed() const {
536  if (m_activity && m_activity->m_actioninfo) {
537  return m_activity->m_actioninfo->m_speed;
538  }
539  return 0;
540  }
541 
543  return this->getFacingLocationRef();
544  }
545 
547  if (!m_facinglocation) {
548  m_facinglocation = new Location(m_location);
549  m_facinglocation->setExactLayerCoordinates(m_facinglocation->getExactLayerCoordinates() + ExactModelCoordinate(1.0, 0.0));
550  //m_facinglocation->setLayerCoordinates(ModelCoordinate(1,0));
551  }
552  return *m_facinglocation;
553  }
554 
556  if (m_activity && m_activity->m_actioninfo) {
557  if(!m_activity->m_timeprovider)
558  bindTimeProvider();
559  return m_activity->m_timeprovider->getGameTime() - m_activity->m_actioninfo->m_action_start_time + m_activity->m_actioninfo->m_action_offset_time;
560  }
561  return getRuntime();
562  }
563 
564  void Instance::setActionRuntime(uint32_t time_offset) {
565  m_activity->m_actioninfo->m_action_offset_time = time_offset;
566  }
567 
568  void Instance::bindTimeProvider() {
569  float multiplier = 1.0;
570  if (m_activity->m_timeprovider) {
571  multiplier = m_activity->m_timeprovider->getMultiplier();
572  }
573  delete m_activity->m_timeprovider;
574  m_activity->m_timeprovider = NULL;
575 
576  if (m_location.getLayer()) {
577  Map* map = m_location.getLayer()->getMap();
578  if (map) {
579  m_activity->m_timeprovider = new TimeProvider(map->getTimeProvider());
580  }
581  }
582  if (!m_activity->m_timeprovider) {
583  m_activity->m_timeprovider = new TimeProvider(NULL);
584  }
585  m_activity->m_timeprovider->setMultiplier(multiplier);
586  }
587 
589  initializeChanges();
590  bindTimeProvider();
591  }
592 
593  void Instance::setTimeMultiplier(float multip) {
594  initializeChanges();
595  if (!m_activity->m_timeprovider) {
596  bindTimeProvider();
597  }
598  m_activity->m_timeprovider->setMultiplier(multip);
599  }
600 
602  if (m_activity && m_activity->m_timeprovider) {
603  return m_activity->m_timeprovider->getMultiplier();
604  }
605  return 1.0;
606  }
607 
609  if (m_activity && m_activity->m_timeprovider) {
610  return m_activity->m_timeprovider->getTotalMultiplier();
611  }
612  if (m_location.getLayer()) {
613  Map* map = m_location.getLayer()->getMap();
614  if (map && map->getTimeProvider()) {
615  return map->getTimeProvider()->getTotalMultiplier();
616  }
617  }
618  return 1.0;
619  }
620 
621  uint32_t Instance::getRuntime() {
622  if (m_activity) {
623  if(!m_activity->m_timeprovider)
624  bindTimeProvider();
625  return m_activity->m_timeprovider->getGameTime();
626  }
627  if (m_location.getLayer()) {
628  Map* map = m_location.getLayer()->getMap();
629  if (map && map->getTimeProvider()) {
630  return map->getTimeProvider()->getGameTime();
631  }
632  }
633  return TimeManager::instance()->getTime();
634  }
635 
636  void Instance::addDeleteListener(InstanceDeleteListener *listener) {
637  m_deletelisteners.push_back(listener);
638  }
639 
640  void Instance::removeDeleteListener(InstanceDeleteListener *listener) {
641  if (!m_deletelisteners.empty()) {
642  std::vector<InstanceDeleteListener*>::iterator itor;
643  itor = std::find(m_deletelisteners.begin(), m_deletelisteners.end(), listener);
644  if(itor != m_deletelisteners.end()) {
645  if ((*itor) == listener) {
646  *itor = NULL;
647  return;
648  }
649  } else {
650  FL_WARN(_log, "Cannot remove unknown listener");
651  }
652  }
653  }
654 
656  if(m_activity && m_activity->m_actioninfo &&
657  m_activity->m_actioninfo->m_leader == instance) {
658  m_activity->m_actioninfo->m_leader = NULL;
659  }
660  }
661 }