comparison engine/core/model/structures/instance.cpp @ 0:4a0efb7baf70

* Datasets becomes the new trunk and retires after that :-)
author mvbarracuda@33b003aa-7bff-0310-803a-e67f0ece8222
date Sun, 29 Jun 2008 18:44:17 +0000
parents
children 90005975cdbb
comparison
equal deleted inserted replaced
-1:000000000000 0:4a0efb7baf70
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 modify *
7 * it under the terms of the GNU General Public License as published by *
8 * the Free Software Foundation; either version 2 of the License, or *
9 * (at your option) any later version. *
10 * *
11 * This program 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 *
14 * GNU General Public License for more details. *
15 * *
16 * You should have received a copy of the GNU General Public License *
17 * along with this program; if not, write to the *
18 * Free Software Foundation, Inc., *
19 * 51 Franklin St, 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 "model/metamodel/grids/cellgrid.h"
36 #include "model/metamodel/abstractpather.h"
37 #include "model/metamodel/action.h"
38 #include "model/metamodel/timeprovider.h"
39 #include "model/structures/layer.h"
40 #include "model/structures/map.h"
41 #include "model/structures/instancetree.h"
42
43 #include "instance.h"
44
45 namespace FIFE {
46 static Logger _log(LM_INSTANCE);
47
48 class ActionInfo {
49 public:
50 ActionInfo(AbstractPather* pather, const Location& curloc):
51 m_action(NULL),
52 m_target(NULL),
53 m_speed(0),
54 m_repeating(false),
55 m_action_start_time(SDL_GetTicks()),
56 m_prev_call_time(m_action_start_time),
57 m_pather_session_id(-1),
58 m_pather(pather),
59 m_leader(NULL) {}
60
61 ~ActionInfo() {
62 if (m_pather_session_id != -1) {
63 m_pather->cancelSession(m_pather_session_id);
64 }
65 delete m_target;
66 m_target = NULL;
67 }
68
69 // Current action, owned by object
70 Action* m_action;
71 // target location for ongoing movement
72 Location* m_target;
73 // current movement speed
74 double m_speed;
75 // should action be repeated? used only for non-moving actions, moving ones repeat until movement is finished
76 bool m_repeating;
77 // action start time (ticks)
78 unsigned int m_action_start_time;
79 // ticks since last call
80 unsigned int m_prev_call_time;
81 // current time for action processing (set by Instance::update), optimized to avoid multiple calls to GetTicks
82 unsigned int m_cur_time;
83 // session id for pather
84 int m_pather_session_id;
85 // pather
86 AbstractPather* m_pather;
87 // leader for follow activity
88 Instance* m_leader;
89 };
90
91 class SayInfo {
92 public:
93 SayInfo(const std::string& txt, unsigned int duration):
94 m_txt(txt),
95 m_duration(duration),
96 m_start_time(SDL_GetTicks()) {
97 }
98 std::string m_txt;
99 unsigned int m_duration;
100 unsigned int m_start_time;
101 };
102
103 Instance::InstanceActivity::InstanceActivity(Instance& source):
104 m_location(source.m_location),
105 m_facinglocation(),
106 m_action(),
107 m_speed(0),
108 m_timemultiplier(1.0),
109 m_saytxt(""),
110 m_changelisteners(),
111 m_actionlisteners(),
112 m_actioninfo(NULL),
113 m_sayinfo(NULL),
114 m_timeprovider(NULL) {
115 if (source.m_facinglocation) {
116 m_facinglocation = *source.m_facinglocation;
117 }
118 }
119
120 Instance::InstanceActivity::~InstanceActivity() {
121 delete m_actioninfo;
122 delete m_sayinfo;
123 delete m_timeprovider;
124 }
125
126 void Instance::InstanceActivity::update(Instance& source) {
127 source.m_changeinfo = ICHANGE_NO_CHANGES;
128 if (m_location != source.m_location) {
129 source.m_changeinfo |= ICHANGE_LOC;
130 m_location = source.m_location;
131 }
132 if (source.m_facinglocation && (m_facinglocation != *source.m_facinglocation)) {
133 source.m_changeinfo |= ICHANGE_FACING_LOC;
134 m_facinglocation = *source.m_facinglocation;
135 }
136 if (m_actioninfo && (m_speed != m_actioninfo->m_speed)) {
137 source.m_changeinfo |= ICHANGE_SPEED;
138 m_speed = m_actioninfo->m_speed;
139 }
140 if (m_actioninfo && (m_action != m_actioninfo->m_action)) {
141 source.m_changeinfo |= ICHANGE_ACTION;
142 m_action = m_actioninfo->m_action;
143 }
144 if (m_timeprovider && (m_timemultiplier != m_timeprovider->getMultiplier())) {
145 source.m_changeinfo |= ICHANGE_TIME_MULTIPLIER;
146 m_timemultiplier = m_timeprovider->getMultiplier();
147 }
148 if (m_sayinfo && (m_saytxt != m_sayinfo->m_txt)) {
149 source.m_changeinfo |= ICHANGE_SAYTEXT;
150 m_saytxt = m_sayinfo->m_txt;
151 }
152
153 if (source.m_changeinfo != ICHANGE_NO_CHANGES) {
154 std::vector<InstanceChangeListener*>::iterator i = m_changelisteners.begin();
155 while (i != m_changelisteners.end()) {
156 (*i)->onInstanceChanged(&source, source.m_changeinfo);
157 ++i;
158 }
159 }
160 }
161
162 Instance::Instance(Object* object, const Location& location, const std::string& identifier):
163 m_id(identifier),
164 m_rotation(0),
165 m_activity(NULL),
166 m_changeinfo(ICHANGE_NO_CHANGES),
167 m_object(object),
168 m_location(location),
169 m_facinglocation(NULL),
170 m_visual(NULL) {
171 }
172
173 Instance::~Instance() {
174 delete m_activity;
175 delete m_facinglocation;
176 delete m_visual;
177 }
178
179 void Instance::initializeChanges() {
180 if (!m_activity) {
181 m_activity = new InstanceActivity(*this);
182 }
183 }
184
185 void Instance::setLocation(const Location& loc) {
186 initializeChanges();
187 m_location = loc;
188 bindTimeProvider();
189 }
190
191 void Instance::setRotation(int rotation) {
192 m_rotation = rotation;
193 m_changeinfo |= ICHANGE_ROTATION;
194 }
195
196 void Instance::addActionListener(InstanceActionListener* listener) {
197 initializeChanges();
198 m_activity->m_actionlisteners.push_back(listener);
199 }
200
201 void Instance::removeActionListener(InstanceActionListener* listener) {
202 if (!m_activity) {
203 return;
204 }
205 std::vector<InstanceActionListener*>::iterator i = m_activity->m_actionlisteners.begin();
206 while (i != m_activity->m_actionlisteners.end()) {
207 if ((*i) == listener) {
208 m_activity->m_actionlisteners.erase(i);
209 return;
210 }
211 ++i;
212 }
213 FL_WARN(_log, "Cannot remove unknown listener");
214 }
215
216 void Instance::addChangeListener(InstanceChangeListener* listener) {
217 initializeChanges();
218 m_activity->m_changelisteners.push_back(listener);
219 }
220
221 void Instance::removeChangeListener(InstanceChangeListener* listener) {
222 if (!m_activity) {
223 return;
224 }
225 std::vector<InstanceChangeListener*>::iterator i = m_activity->m_changelisteners.begin();
226 while (i != m_activity->m_changelisteners.end()) {
227 if ((*i) == listener) {
228 m_activity->m_changelisteners.erase(i);
229 return;
230 }
231 ++i;
232 }
233 FL_WARN(_log, "Cannot remove unknown listener");
234 }
235
236 void Instance::initalizeAction(const std::string& action_name) {
237 assert(m_object);
238 assert(m_activity);
239 if (m_activity->m_actioninfo) {
240 delete m_activity->m_actioninfo;
241 m_activity->m_actioninfo = NULL;
242 }
243 m_activity->m_actioninfo = new ActionInfo(m_object->getPather(), m_location);
244 m_activity->m_actioninfo->m_action = m_object->getAction(action_name);
245 if (!m_activity->m_actioninfo->m_action) {
246 delete m_activity->m_actioninfo;
247 m_activity->m_actioninfo = NULL;
248 throw NotFound(std::string("action ") + action_name + " not found");
249 }
250 }
251
252 void Instance::move(const std::string& action_name, const Location& target, const double speed) {
253 initializeChanges();
254 initalizeAction(action_name);
255 m_activity->m_actioninfo->m_target = new Location(target);
256 m_activity->m_actioninfo->m_speed = speed;
257 setFacingLocation(target);
258 FL_DBG(_log, LMsg("starting action ") << action_name << " from" << m_location << " to " << target << " with speed " << speed);
259 }
260
261 void Instance::follow(const std::string& action_name, Instance* leader, const double speed) {
262 initializeChanges();
263 initalizeAction(action_name);
264 m_activity->m_actioninfo->m_target = new Location(leader->getLocationRef());
265 m_activity->m_actioninfo->m_speed = speed;
266 m_activity->m_actioninfo->m_leader = leader;
267 setFacingLocation(*m_activity->m_actioninfo->m_target);
268 FL_DBG(_log, LMsg("starting action ") << action_name << " from" << m_location << " to " << *m_activity->m_actioninfo->m_target << " with speed " << speed);
269 }
270
271 void Instance::act(const std::string& action_name, const Location& direction, bool repeating) {
272 initializeChanges();
273 initalizeAction(action_name);
274 m_activity->m_actioninfo->m_repeating = repeating;
275 setFacingLocation(direction);
276 }
277
278 void Instance::say(const std::string& text, unsigned int duration) {
279 initializeChanges();
280 delete m_activity->m_sayinfo;
281 m_activity->m_sayinfo = NULL;
282
283 if (text != "") {
284 m_activity->m_sayinfo = new SayInfo(text, duration);
285 }
286 }
287
288 const std::string* Instance::getSayText() const {
289 if (m_activity && m_activity->m_sayinfo) {
290 return &m_activity->m_sayinfo->m_txt;
291 }
292 return NULL;
293 }
294
295 void Instance::setFacingLocation(const Location& loc) {
296 if (!m_facinglocation) {
297 m_facinglocation = new Location(loc);
298 } else {
299 *m_facinglocation = loc;
300 }
301 }
302
303 bool Instance::process_movement() {
304 FL_DBG(_log, "Moving...");
305 ActionInfo* info = m_activity->m_actioninfo;
306 // timeslice for this movement
307 unsigned int timedelta = scaleTime(getTotalTimeMultiplier(), info->m_cur_time - info->m_prev_call_time);
308 FL_DBG(_log, LMsg("timedelta ") << timedelta << " prevcalltime " << info->m_prev_call_time);
309 // how far we can travel
310 double distance_to_travel = (static_cast<double>(timedelta) / 1000.0) * info->m_speed;
311 FL_DBG(_log, LMsg("dist ") << distance_to_travel);
312
313 Location nextLocation = m_location;
314 info->m_pather_session_id = info->m_pather->getNextLocation(
315 this, *info->m_target,
316 distance_to_travel, nextLocation, *m_facinglocation,
317 info->m_pather_session_id);
318 m_location.getLayer()->getInstanceTree()->removeInstance(this);
319 m_location = nextLocation;
320 //ExactModelCoordinate a = nextLocation.getMapCoordinates();
321 //ExactModelCoordinate b = m_actioninfo->m_target->getMapCoordinates();
322 m_location.getLayer()->getInstanceTree()->addInstance(this);
323 // return if we are close enough to target to stop
324 if (info->m_pather_session_id == -1) {
325 return true;
326 }
327 return false;
328 }
329
330 InstanceChangeInfo Instance::update(unsigned int curticks) {
331 if (!m_activity) {
332 return ICHANGE_NO_CHANGES;
333 }
334 m_activity->update(*this);
335 if (!m_activity->m_timeprovider) {
336 bindTimeProvider();
337 }
338
339 if (curticks == 0) {
340 curticks = SDL_GetTicks();
341 }
342 ActionInfo* info = m_activity->m_actioninfo;
343 if (info) {
344 info->m_cur_time = curticks;
345 FL_DBG(_log, LMsg("updating instance, ticks = ") << curticks);
346
347 if (info->m_target) {
348 FL_DBG(_log, "action contains target for movement");
349 // update target if needed
350 if (info->m_leader && (info->m_leader->getLocationRef() != *info->m_target)) {
351 *info->m_target = info->m_leader->getLocation();
352 }
353 bool movement_finished = process_movement();
354 if (movement_finished) {
355 FL_DBG(_log, "movement finished");
356 finalizeAction();
357 }
358 } else {
359 FL_DBG(_log, "action does not contain target for movement");
360 if (scaleTime(getTotalTimeMultiplier(), curticks - info->m_action_start_time) >= info->m_action->getDuration()) {
361 if (info->m_repeating) {
362 info->m_action_start_time = curticks;
363 } else {
364 finalizeAction();
365 }
366 }
367 }
368
369 m_activity->m_actioninfo->m_prev_call_time = curticks;
370 }
371 if (m_activity->m_sayinfo) {
372 if (m_activity->m_sayinfo->m_duration > 0) {
373 if (scaleTime(getTotalTimeMultiplier(), curticks - m_activity->m_sayinfo->m_start_time) > m_activity->m_sayinfo->m_duration) {
374 say("");
375 }
376 }
377 }
378 return m_changeinfo;
379 }
380
381 void Instance::finalizeAction() {
382 FL_DBG(_log, "finalizing action");
383 assert(m_activity);
384 assert(m_activity->m_actioninfo);
385
386 Action* action = m_activity->m_actioninfo->m_action;
387 delete m_activity->m_actioninfo;
388 m_activity->m_actioninfo = NULL;
389
390 std::vector<InstanceActionListener*>::iterator i = m_activity->m_actionlisteners.begin();
391 while (i != m_activity->m_actionlisteners.end()) {
392 (*i)->onInstanceActionFinished(this, action);
393 ++i;
394 }
395 }
396
397 Action* Instance::getCurrentAction() const {
398 if (m_activity && m_activity->m_actioninfo) {
399 return m_activity->m_actioninfo->m_action;
400 }
401 return NULL;
402 }
403
404 Location Instance::getTargetLocation() const {
405 if (m_activity && m_activity->m_actioninfo && m_activity->m_actioninfo->m_target) {
406 return *m_activity->m_actioninfo->m_target;
407 }
408 return m_location;
409 }
410
411 double Instance::getMovementSpeed() const {
412 if (m_activity && m_activity->m_actioninfo) {
413 return m_activity->m_actioninfo->m_speed;
414 }
415 return 0;
416 }
417
418 Location Instance::getFacingLocation() {
419 return this->getFacingLocationRef();
420 }
421
422 Location& Instance::getFacingLocationRef() {
423 if (!m_facinglocation) {
424 m_facinglocation = new Location(m_location);
425 m_facinglocation->setExactLayerCoordinates(m_facinglocation->getExactLayerCoordinates() + ExactModelCoordinate(1.0, 0.0));
426 //m_facinglocation->setLayerCoordinates(ModelCoordinate(1,0));
427 }
428 return *m_facinglocation;
429 }
430
431 int Instance::getActionRuntime() const {
432 if (m_activity && m_activity->m_actioninfo) {
433 return SDL_GetTicks() - m_activity->m_actioninfo->m_action_start_time;
434 }
435 return -1;
436 }
437
438 void Instance::bindTimeProvider() {
439 float multiplier = 1.0;
440 if (m_activity->m_timeprovider) {
441 multiplier = m_activity->m_timeprovider->getMultiplier();
442 }
443 delete m_activity->m_timeprovider;
444 m_activity->m_timeprovider = NULL;
445
446 if (m_location.getLayer()) {
447 Map* map = m_location.getLayer()->getMap();
448 if (map) {
449 m_activity->m_timeprovider = new TimeProvider(map->getTimeProvider());
450 }
451 }
452 if (!m_activity->m_timeprovider) {
453 m_activity->m_timeprovider = new TimeProvider(NULL);
454 }
455 m_activity->m_timeprovider->setMultiplier(multiplier);
456 }
457
458 void Instance::refresh() {
459 initializeChanges();
460 bindTimeProvider();
461 }
462
463 void Instance::setTimeMultiplier(float multip) {
464 initializeChanges();
465 if (!m_activity->m_timeprovider) {
466 bindTimeProvider();
467 }
468 m_activity->m_timeprovider->setMultiplier(multip);
469 }
470
471 float Instance::getTimeMultiplier() {
472 if (m_activity && m_activity->m_timeprovider) {
473 return m_activity->m_timeprovider->getMultiplier();
474 }
475 return 1.0;
476 }
477
478 float Instance::getTotalTimeMultiplier() {
479 if (m_activity && m_activity->m_timeprovider) {
480 return m_activity->m_timeprovider->getTotalMultiplier();
481 }
482 return 1.0;
483 }
484 }
485