Mercurial > fife-parpg
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 |