FIFE  2008.0
 All Classes Namespaces Functions Variables Enumerations Enumerator Pages
instance.cpp
1 /***************************************************************************
2  * Copyright (C) 2005-2008 by the FIFE team *
3  * http://www.fifengine.de *
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/abstractpather.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(AbstractPather* 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  unsigned int m_action_start_time;
81  // action offset time (ticks) for resuming an action
82  unsigned int m_action_offset_time;
83  // ticks since last call
84  unsigned int m_prev_call_time;
85  // session id for pather
86  int m_pather_session_id;
87  // pather
88  AbstractPather* m_pather;
89  // leader for follow activity
90  Instance* m_leader;
91  };
92 
93  class SayInfo {
94  public:
95  SayInfo(const std::string& txt, unsigned int duration):
96  m_txt(txt),
97  m_duration(duration),
98  m_start_time(0) {}
99 
100  std::string m_txt;
101  unsigned int m_duration;
102  unsigned int 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  if (source.m_facinglocation) {
119  m_facinglocation = *source.m_facinglocation;
120  }
121  }
122 
123  Instance::InstanceActivity::~InstanceActivity() {
124  delete m_actioninfo;
125  delete m_sayinfo;
126  delete m_timeprovider;
127  }
128 
129  void Instance::InstanceActivity::update(Instance& source) {
130  source.m_changeinfo = ICHANGE_NO_CHANGES;
131  if (m_location != source.m_location) {
132  source.m_changeinfo |= ICHANGE_LOC;
133  m_location = source.m_location;
134  }
135  if (m_rotation != source.m_rotation) {
136  source.m_changeinfo |= ICHANGE_ROTATION;
137  m_rotation = source.m_rotation;
138  }
139  if (source.m_facinglocation && (m_facinglocation != *source.m_facinglocation)) {
140  source.m_changeinfo |= ICHANGE_FACING_LOC;
141  m_facinglocation = *source.m_facinglocation;
142  }
143  if (m_actioninfo && (m_speed != m_actioninfo->m_speed)) {
144  source.m_changeinfo |= ICHANGE_SPEED;
145  m_speed = m_actioninfo->m_speed;
146  }
147  if (m_actioninfo && (m_action != m_actioninfo->m_action)) {
148  source.m_changeinfo |= ICHANGE_ACTION;
149  m_action = m_actioninfo->m_action;
150  }
151  if (m_timeprovider && (m_timemultiplier != m_timeprovider->getMultiplier())) {
152  source.m_changeinfo |= ICHANGE_TIME_MULTIPLIER;
153  m_timemultiplier = m_timeprovider->getMultiplier();
154  }
155  if (m_sayinfo && (m_saytxt != m_sayinfo->m_txt)) {
156  source.m_changeinfo |= ICHANGE_SAYTEXT;
157  m_saytxt = m_sayinfo->m_txt;
158  }
159 
160  if (source.m_changeinfo != ICHANGE_NO_CHANGES) {
161  std::vector<InstanceChangeListener*>::iterator i = m_changelisteners.begin();
162  while (i != m_changelisteners.end()) {
163  if (NULL != *i)
164  {
165  (*i)->onInstanceChanged(&source, source.m_changeinfo);
166  }
167  ++i;
168  }
169  // Really remove "removed" listeners.
170  m_changelisteners.erase(
171  std::remove(m_changelisteners.begin(),m_changelisteners.end(),
172  (InstanceChangeListener*)NULL),
173  m_changelisteners.end());
174  }
175  }
176 
177  Instance::Instance(Object* object, const Location& location, const std::string& identifier):
178  m_id(identifier),
179  m_rotation(0),
180  m_activity(NULL),
181  m_changeinfo(ICHANGE_NO_CHANGES),
182  m_object(object),
183  m_location(location),
184  m_facinglocation(NULL),
185  m_visual(NULL),
186  m_blocking(object->isBlocking()),
187  m_override_blocking(false) {
188  }
189 
191  std::vector<InstanceDeleteListener *>::iterator itor;
192  for(itor = m_deletelisteners.begin();
193  itor != m_deletelisteners.end();
194  ++itor) {
195  (*itor)->onInstanceDeleted(this);
196  }
197 
198  if(m_activity && m_activity->m_actioninfo) {
199  // Don't ditribute onActionFinished in case we're already
200  // deleting.
201  m_activity->m_actionlisteners.clear();
202  finalizeAction();
203  }
204 
205  delete m_activity;
206  delete m_facinglocation;
207  delete m_visual;
208  }
209 
210  void Instance::initializeChanges() {
211  if (!m_activity) {
212  m_activity = new InstanceActivity(*this);
213  if(m_location.getLayer()) {
214  m_location.getLayer()->setInstanceActivityStatus(this, true);
215  }
216  }
217  }
218 
219  bool Instance::isActive() const {
220  return bool(m_activity);
221  }
222 
223  void Instance::setLocation(const Location& loc) {
224  if(m_location != loc) {
225  m_location = loc;
226  if(isActive()) {
227  refresh();
228  } else {
229  initializeChanges();
230  }
231  }
232  }
233 
234  void Instance::setRotation(int rotation) {
235  if(m_rotation != rotation) {
236  m_rotation = rotation;
237  if(isActive()) {
238  refresh();
239  } else {
240  initializeChanges();
241  }
242  }
243  }
244 
245  void Instance::setId(const std::string& identifier) {
246  m_id = identifier;
247  }
248 
249  void Instance::setBlocking(bool blocking) {
250  if (m_override_blocking) {
251  m_blocking = blocking;
252  }
253  }
254 
255  bool Instance::isBlocking() const {
256  return m_blocking;
257  }
258 
259  void Instance::addActionListener(InstanceActionListener* listener) {
260  initializeChanges();
261  m_activity->m_actionlisteners.push_back(listener);
262  }
263 
264  void Instance::removeActionListener(InstanceActionListener* listener) {
265  if (!m_activity) {
266  return;
267  }
268  std::vector<InstanceActionListener*>::iterator i = m_activity->m_actionlisteners.begin();
269  while (i != m_activity->m_actionlisteners.end()) {
270  if ((*i) == listener) {
271  *i = NULL;
272  return;
273  }
274  ++i;
275  }
276  FL_WARN(_log, "Cannot remove unknown listener");
277  }
278 
279  void Instance::addChangeListener(InstanceChangeListener* listener) {
280  initializeChanges();
281  m_activity->m_changelisteners.push_back(listener);
282  }
283 
284  void Instance::removeChangeListener(InstanceChangeListener* listener) {
285  if (!m_activity) {
286  return;
287  }
288  std::vector<InstanceChangeListener*>::iterator i = m_activity->m_changelisteners.begin();
289  while (i != m_activity->m_changelisteners.end()) {
290  if ((*i) == listener) {
291  *i = NULL;
292  return;
293  }
294  ++i;
295  }
296  FL_WARN(_log, "Cannot remove unknown listener");
297  }
298  void Instance::initializeAction(const std::string& action_name) {
299  assert(m_object);
300  assert(m_activity);
301  const Action *old_action = m_activity->m_actioninfo ? m_activity->m_actioninfo->m_action : NULL;
302  if (m_activity->m_actioninfo) {
303  delete m_activity->m_actioninfo;
304  m_activity->m_actioninfo = NULL;
305  }
306  m_activity->m_actioninfo = new ActionInfo(m_object->getPather(), m_location);
307  m_activity->m_actioninfo->m_action = m_object->getAction(action_name);
308  if (!m_activity->m_actioninfo->m_action) {
309  delete m_activity->m_actioninfo;
310  m_activity->m_actioninfo = NULL;
311  throw NotFound(std::string("action ") + action_name + " not found");
312  }
313  m_activity->m_actioninfo->m_prev_call_time = getRuntime();
314  if (m_activity->m_actioninfo->m_action != old_action) {
315  m_activity->m_actioninfo->m_action_start_time = m_activity->m_actioninfo->m_prev_call_time;
316  }
317  }
318 
319  void Instance::move(const std::string& action_name, const Location& target, const double speed) {
320  initializeChanges();
321  initializeAction(action_name);
322  m_activity->m_actioninfo->m_target = new Location(target);
323  m_activity->m_actioninfo->m_speed = speed;
324  setFacingLocation(target);
325  FL_DBG(_log, LMsg("starting action ") << action_name << " from" << m_location << " to " << target << " with speed " << speed);
326  }
327 
328  void Instance::follow(const std::string& action_name, Instance* leader, const double speed) {
329  initializeChanges();
330  initializeAction(action_name);
331  m_activity->m_actioninfo->m_target = new Location(leader->getLocationRef());
332  m_activity->m_actioninfo->m_speed = speed;
333  m_activity->m_actioninfo->m_leader = leader;
334  leader->addDeleteListener(this);
335  setFacingLocation(*m_activity->m_actioninfo->m_target);
336  FL_DBG(_log, LMsg("starting action ") << action_name << " from" << m_location << " to " << *m_activity->m_actioninfo->m_target << " with speed " << speed);
337  }
338 
339  void Instance::act(const std::string& action_name, const Location& direction, bool repeating) {
340  initializeChanges();
341  initializeAction(action_name);
342  m_activity->m_actioninfo->m_repeating = repeating;
343  setFacingLocation(direction);
344  }
345 
346  void Instance::say(const std::string& text, unsigned int duration) {
347  initializeChanges();
348  delete m_activity->m_sayinfo;
349  m_activity->m_sayinfo = NULL;
350 
351  if (text != "") {
352  m_activity->m_sayinfo = new SayInfo(text, duration);
353  m_activity->m_sayinfo->m_start_time = getRuntime();
354  }
355  }
356 
357  const std::string* Instance::getSayText() const {
358  if (m_activity && m_activity->m_sayinfo) {
359  return &m_activity->m_sayinfo->m_txt;
360  }
361  return NULL;
362  }
363 
364  void Instance::setFacingLocation(const Location& loc) {
365  if (!m_facinglocation) {
366  m_facinglocation = new Location(loc);
367  } else {
368  *m_facinglocation = loc;
369  }
370  }
371 
372  bool Instance::process_movement() {
373  FL_DBG(_log, "Moving...");
374  ActionInfo* info = m_activity->m_actioninfo;
375  // timeslice for this movement
376  unsigned int timedelta = m_activity->m_timeprovider->getGameTime() - info->m_prev_call_time;
377  FL_DBG(_log, LMsg("timedelta ") << timedelta << " prevcalltime " << info->m_prev_call_time);
378  // how far we can travel
379  double distance_to_travel = (static_cast<double>(timedelta) / 1000.0) * info->m_speed;
380  FL_DBG(_log, LMsg("dist ") << distance_to_travel);
381 
382  Location nextLocation = m_location;
383  info->m_pather_session_id = info->m_pather->getNextLocation(
384  this, *info->m_target,
385  distance_to_travel, nextLocation, *m_facinglocation,
386  info->m_pather_session_id);
387  m_location.getLayer()->getInstanceTree()->removeInstance(this);
388  m_location = nextLocation;
389  //ExactModelCoordinate a = nextLocation.getMapCoordinates();
390  //ExactModelCoordinate b = m_actioninfo->m_target->getMapCoordinates();
391  m_location.getLayer()->getInstanceTree()->addInstance(this);
392  // return if we are close enough to target to stop
393  if (info->m_pather_session_id == -1) {
394  return true;
395  }
396  return false;
397  }
398 
399  InstanceChangeInfo Instance::update() {
400  if (!m_activity) {
401  return ICHANGE_NO_CHANGES;
402  }
403  m_activity->update(*this);
404  if (!m_activity->m_timeprovider) {
405  bindTimeProvider();
406  }
407  ActionInfo* info = m_activity->m_actioninfo;
408  if (info) {
409  FL_DBG(_log, "updating instance");
410 
411  if (info->m_target) {
412  FL_DBG(_log, "action contains target for movement");
413  // update target if needed
414  if (info->m_leader && (info->m_leader->getLocationRef() != *info->m_target)) {
415  *info->m_target = info->m_leader->getLocation();
416  }
417  bool movement_finished = process_movement();
418  if (movement_finished) {
419  FL_DBG(_log, "movement finished");
420  finalizeAction();
421  }
422  } else {
423  FL_DBG(_log, "action does not contain target for movement");
424  if (m_activity->m_timeprovider->getGameTime() - info->m_action_start_time + info->m_action_offset_time >= info->m_action->getDuration()) {
425  if (info->m_repeating) {
426  info->m_action_start_time = m_activity->m_timeprovider->getGameTime();
427  // prock: offset no longer needed
428  info->m_action_offset_time = 0;
429  } else {
430  finalizeAction();
431  }
432  }
433  }
434 
435  // previous code may invalidate actioninfo.
436  if( m_activity->m_actioninfo ) {
437  m_activity->m_actioninfo->m_prev_call_time = m_activity->m_timeprovider->getGameTime();
438  }
439  }
440  if (m_activity->m_sayinfo) {
441  if (m_activity->m_sayinfo->m_duration > 0) {
442  if (m_activity->m_timeprovider->getGameTime() >= m_activity->m_sayinfo->m_start_time + m_activity->m_sayinfo->m_duration) {
443  say("");
444  }
445  }
446  }
447  return m_changeinfo;
448  }
449 
450  void Instance::finalizeAction() {
451  FL_DBG(_log, "finalizing action");
452  assert(m_activity);
453  assert(m_activity->m_actioninfo);
454 
455  if( m_activity->m_actioninfo->m_leader ) {
456  m_activity->m_actioninfo->m_leader->removeDeleteListener(this);
457  }
458 
459  Action* action = m_activity->m_actioninfo->m_action;
460  delete m_activity->m_actioninfo;
461  m_activity->m_actioninfo = NULL;
462 
463  std::vector<InstanceActionListener*>::iterator i = m_activity->m_actionlisteners.begin();
464  while (i != m_activity->m_actionlisteners.end()) {
465  if(*i)
466  (*i)->onInstanceActionFinished(this, action);
467  ++i;
468  }
469  m_activity->m_actionlisteners.erase(
470  std::remove(m_activity->m_actionlisteners.begin(),
471  m_activity->m_actionlisteners.end(),
472  (InstanceActionListener*)NULL),
473  m_activity->m_actionlisteners.end());
474  }
475 
476  Action* Instance::getCurrentAction() const {
477  if (m_activity && m_activity->m_actioninfo) {
478  return m_activity->m_actioninfo->m_action;
479  }
480  return NULL;
481  }
482 
483  Location Instance::getTargetLocation() const {
484  if (m_activity && m_activity->m_actioninfo && m_activity->m_actioninfo->m_target) {
485  return *m_activity->m_actioninfo->m_target;
486  }
487  return m_location;
488  }
489 
490  double Instance::getMovementSpeed() const {
491  if (m_activity && m_activity->m_actioninfo) {
492  return m_activity->m_actioninfo->m_speed;
493  }
494  return 0;
495  }
496 
498  return this->getFacingLocationRef();
499  }
500 
502  if (!m_facinglocation) {
503  m_facinglocation = new Location(m_location);
504  m_facinglocation->setExactLayerCoordinates(m_facinglocation->getExactLayerCoordinates() + ExactModelCoordinate(1.0, 0.0));
505  //m_facinglocation->setLayerCoordinates(ModelCoordinate(1,0));
506  }
507  return *m_facinglocation;
508  }
509 
510  unsigned int Instance::getActionRuntime() {
511  if (m_activity && m_activity->m_actioninfo) {
512  if(!m_activity->m_timeprovider)
513  bindTimeProvider();
514  return m_activity->m_timeprovider->getGameTime() - m_activity->m_actioninfo->m_action_start_time + m_activity->m_actioninfo->m_action_offset_time;
515  }
516  return getRuntime();
517  }
518 
519  void Instance::setActionRuntime(unsigned int time_offset) {
520  m_activity->m_actioninfo->m_action_offset_time = time_offset;
521  }
522 
523  void Instance::bindTimeProvider() {
524  float multiplier = 1.0;
525  if (m_activity->m_timeprovider) {
526  multiplier = m_activity->m_timeprovider->getMultiplier();
527  }
528  delete m_activity->m_timeprovider;
529  m_activity->m_timeprovider = NULL;
530 
531  if (m_location.getLayer()) {
532  Map* map = m_location.getLayer()->getMap();
533  if (map) {
534  m_activity->m_timeprovider = new TimeProvider(map->getTimeProvider());
535  }
536  }
537  if (!m_activity->m_timeprovider) {
538  m_activity->m_timeprovider = new TimeProvider(NULL);
539  }
540  m_activity->m_timeprovider->setMultiplier(multiplier);
541  }
542 
544  initializeChanges();
545  bindTimeProvider();
546  }
547 
548  void Instance::setTimeMultiplier(float multip) {
549  initializeChanges();
550  if (!m_activity->m_timeprovider) {
551  bindTimeProvider();
552  }
553  m_activity->m_timeprovider->setMultiplier(multip);
554  }
555 
557  if (m_activity && m_activity->m_timeprovider) {
558  return m_activity->m_timeprovider->getMultiplier();
559  }
560  return 1.0;
561  }
562 
564  if (m_activity && m_activity->m_timeprovider) {
565  return m_activity->m_timeprovider->getTotalMultiplier();
566  }
567  if (m_location.getLayer()) {
568  Map* map = m_location.getLayer()->getMap();
569  if (map && map->getTimeProvider()) {
570  return map->getTimeProvider()->getTotalMultiplier();
571  }
572  }
573  return 1.0;
574  }
575 
576  unsigned int Instance::getRuntime() {
577  if (m_activity) {
578  if(!m_activity->m_timeprovider)
579  bindTimeProvider();
580  return m_activity->m_timeprovider->getGameTime();
581  }
582  if (m_location.getLayer()) {
583  Map* map = m_location.getLayer()->getMap();
584  if (map && map->getTimeProvider()) {
585  return map->getTimeProvider()->getGameTime();
586  }
587  }
588  return TimeManager::instance()->getTime();
589  }
590  void Instance::addDeleteListener(InstanceDeleteListener *listener) {
591  m_deletelisteners.push_back(listener);
592  }
593  void Instance::removeDeleteListener(InstanceDeleteListener *listener) {
594  std::vector<InstanceDeleteListener*>::iterator itor;
595  itor = std::find(m_deletelisteners.begin(),
596  m_deletelisteners.end(),
597  listener);
598  if(itor != m_deletelisteners.end()) {
599  m_deletelisteners.erase(itor);
600  } else {
601  FL_WARN(_log, "Cannot remove unknown listener");
602  }
603  }
605  if(m_activity &&
606  m_activity->m_actioninfo &&
607  m_activity->m_actioninfo->m_leader == instance) {
608  m_activity->m_actioninfo->m_leader = NULL;
609  }
610  }
611 }