instance.cpp

00001 /***************************************************************************
00002  *   Copyright (C) 2005-2008 by the FIFE team                              *
00003  *   http://www.fifengine.de                                               *
00004  *   This file is part of FIFE.                                            *
00005  *                                                                         *
00006  *   FIFE is free software; you can redistribute it and/or                 *
00007  *   modify it under the terms of the GNU Lesser General Public            *
00008  *   License as published by the Free Software Foundation; either          *
00009  *   version 2.1 of the License, or (at your option) any later version.    *
00010  *                                                                         *
00011  *   This library is distributed in the hope that it will be useful,       *
00012  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00013  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
00014  *   Lesser General Public License for more details.                       *
00015  *                                                                         *
00016  *   You should have received a copy of the GNU Lesser General Public      *
00017  *   License along with this library; if not, write to the                 *
00018  *   Free Software Foundation, Inc.,                                       *
00019  *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA          *
00020  ***************************************************************************/
00021 
00022 // Standard C++ library includes
00023 #include <iostream>
00024 
00025 // 3rd party library includes
00026 #include <SDL.h>
00027 
00028 // FIFE includes
00029 // These includes are split up in two parts, separated by one empty line
00030 // First block: files included from the FIFE root src directory
00031 // Second block: files included from the same folder
00032 #include "util/log/logger.h"
00033 #include "util/base/exception.h"
00034 #include "util/math/fife_math.h"
00035 #include "util/time/timemanager.h"
00036 #include "model/metamodel/grids/cellgrid.h"
00037 #include "model/metamodel/abstractpather.h"
00038 #include "model/metamodel/action.h"
00039 #include "model/metamodel/timeprovider.h"
00040 #include "model/structures/layer.h"
00041 #include "model/structures/map.h"
00042 #include "model/structures/instancetree.h"
00043 
00044 #include "instance.h"
00045 
00046 namespace FIFE {
00047     static Logger _log(LM_INSTANCE);
00048 
00049     class ActionInfo {
00050     public:
00051         ActionInfo(AbstractPather* pather, const Location& curloc):
00052             m_action(NULL),
00053             m_target(NULL),
00054             m_speed(0),
00055             m_repeating(false),
00056             m_action_start_time(0),
00057             m_action_offset_time(0),
00058             m_prev_call_time(0),
00059             m_pather_session_id(-1),
00060             m_pather(pather),
00061             m_leader(NULL) {}
00062 
00063         ~ActionInfo() {
00064             if (m_pather_session_id != -1) {
00065                 m_pather->cancelSession(m_pather_session_id);
00066             }
00067             delete m_target;
00068             m_target = NULL;
00069         }
00070 
00071         // Current action, owned by object
00072         Action* m_action;
00073         // target location for ongoing movement
00074         Location* m_target;
00075         // current movement speed
00076         double m_speed;
00077         // should action be repeated? used only for non-moving actions, moving ones repeat until movement is finished
00078         bool m_repeating;
00079         // action start time (ticks)
00080         unsigned int m_action_start_time;
00081         // action offset time (ticks) for resuming an action
00082         unsigned int m_action_offset_time;
00083         // ticks since last call
00084         unsigned int m_prev_call_time;
00085         // session id for pather
00086         int m_pather_session_id;
00087         // pather
00088         AbstractPather* m_pather;
00089         // leader for follow activity
00090         Instance* m_leader;
00091     };
00092 
00093     class SayInfo {
00094     public:
00095         SayInfo(const std::string& txt, unsigned int duration):
00096             m_txt(txt),
00097             m_duration(duration),
00098             m_start_time(0) {}
00099 
00100         std::string m_txt;
00101         unsigned int m_duration;
00102         unsigned int m_start_time;
00103     };
00104 
00105     Instance::InstanceActivity::InstanceActivity(Instance& source):
00106         m_location(source.m_location),
00107         m_facinglocation(),
00108         m_action(),
00109         m_speed(0),
00110         m_timemultiplier(1.0),
00111         m_saytxt(""),
00112         m_changelisteners(),
00113         m_actionlisteners(),
00114         m_actioninfo(NULL),
00115         m_sayinfo(NULL),
00116         m_timeprovider(NULL) {
00117         if (source.m_facinglocation) {
00118             m_facinglocation = *source.m_facinglocation;
00119         }
00120     }
00121 
00122     Instance::InstanceActivity::~InstanceActivity() {
00123         delete m_actioninfo;
00124         delete m_sayinfo;
00125         delete m_timeprovider;
00126     }
00127 
00128     void Instance::InstanceActivity::update(Instance& source) {
00129         source.m_changeinfo = ICHANGE_NO_CHANGES;
00130         if (m_location != source.m_location) {
00131             source.m_changeinfo |= ICHANGE_LOC;
00132             m_location = source.m_location;
00133         }
00134         if (source.m_facinglocation && (m_facinglocation != *source.m_facinglocation)) {
00135             source.m_changeinfo |= ICHANGE_FACING_LOC;
00136             m_facinglocation = *source.m_facinglocation;
00137         }
00138         if (m_actioninfo && (m_speed != m_actioninfo->m_speed)) {
00139             source.m_changeinfo |= ICHANGE_SPEED;
00140             m_speed = m_actioninfo->m_speed;
00141         }
00142         if (m_actioninfo && (m_action != m_actioninfo->m_action)) {
00143             source.m_changeinfo |= ICHANGE_ACTION;
00144             m_action = m_actioninfo->m_action;
00145         }
00146         if (m_timeprovider && (m_timemultiplier != m_timeprovider->getMultiplier())) {
00147             source.m_changeinfo |= ICHANGE_TIME_MULTIPLIER;
00148             m_timemultiplier = m_timeprovider->getMultiplier();
00149         }
00150         if (m_sayinfo && (m_saytxt != m_sayinfo->m_txt)) {
00151             source.m_changeinfo |= ICHANGE_SAYTEXT;
00152             m_saytxt = m_sayinfo->m_txt;
00153         }
00154 
00155         if (source.m_changeinfo != ICHANGE_NO_CHANGES) {
00156             std::vector<InstanceChangeListener*>::iterator i = m_changelisteners.begin();
00157             while (i != m_changelisteners.end()) {
00158                 if (NULL != *i)
00159                 {
00160                     (*i)->onInstanceChanged(&source, source.m_changeinfo);
00161                 }
00162                 ++i;
00163             }
00164             // Really remove "removed" listeners.
00165             m_changelisteners.erase(
00166                 std::remove(m_changelisteners.begin(),m_changelisteners.end(),
00167                     (InstanceChangeListener*)NULL),
00168                 m_changelisteners.end());
00169         }
00170     }
00171 
00172     Instance::Instance(Object* object, const Location& location, const std::string& identifier):
00173         m_id(identifier),
00174         m_rotation(0),
00175         m_activity(NULL),
00176         m_changeinfo(ICHANGE_NO_CHANGES),
00177         m_object(object),
00178         m_location(location),
00179         m_facinglocation(NULL),
00180         m_visual(NULL) {
00181     }
00182 
00183     Instance::~Instance() {
00184         std::vector<InstanceDeleteListener *>::iterator itor;
00185         for(itor = m_deletelisteners.begin();
00186             itor != m_deletelisteners.end();
00187             ++itor) {
00188                 (*itor)->onInstanceDeleted(this);
00189         }
00190 
00191         if(m_activity && m_activity->m_actioninfo) {
00192             // Don't ditribute onActionFinished in case we're already
00193             // deleting.
00194             m_activity->m_actionlisteners.clear();
00195             finalizeAction();
00196         }
00197 
00198         delete m_activity;
00199         delete m_facinglocation;
00200         delete m_visual;
00201     }
00202 
00203     void Instance::initializeChanges() {
00204         if (!m_activity) {
00205             m_activity = new InstanceActivity(*this);
00206         }
00207     }
00208 
00209     void Instance::setLocation(const Location& loc) {
00210         initializeChanges();
00211         m_location = loc;
00212         bindTimeProvider();
00213     }
00214 
00215     void Instance::setRotation(int rotation) {
00216         m_rotation = rotation;
00217         m_changeinfo |= ICHANGE_ROTATION;
00218     }
00219 
00220     void Instance::setId(const std::string& identifier) {
00221         m_id = identifier;
00222     }
00223 
00224     void Instance::addActionListener(InstanceActionListener* listener) {
00225         initializeChanges();
00226         m_activity->m_actionlisteners.push_back(listener);
00227     }
00228 
00229     void Instance::removeActionListener(InstanceActionListener* listener) {
00230         if (!m_activity) {
00231             return;
00232         }
00233         std::vector<InstanceActionListener*>::iterator i = m_activity->m_actionlisteners.begin();
00234         while (i != m_activity->m_actionlisteners.end()) {
00235             if ((*i) == listener) {
00236                 *i = NULL;
00237                 return;
00238             }
00239             ++i;
00240         }
00241         FL_WARN(_log, "Cannot remove unknown listener");
00242     }
00243 
00244     void Instance::addChangeListener(InstanceChangeListener* listener) {
00245         initializeChanges();
00246         m_activity->m_changelisteners.push_back(listener);
00247     }
00248 
00249     void Instance::removeChangeListener(InstanceChangeListener* listener) {
00250         if (!m_activity) {
00251             return;
00252         }
00253         std::vector<InstanceChangeListener*>::iterator i = m_activity->m_changelisteners.begin();
00254         while (i != m_activity->m_changelisteners.end()) {
00255             if ((*i) == listener) {
00256                 *i = NULL;
00257                 return;
00258             }
00259             ++i;
00260         }
00261         FL_WARN(_log, "Cannot remove unknown listener");
00262     }
00263     void Instance::initializeAction(const std::string& action_name) {
00264         assert(m_object);
00265         assert(m_activity);
00266         const Action *old_action = m_activity->m_actioninfo ? m_activity->m_actioninfo->m_action : NULL;
00267         if (m_activity->m_actioninfo) {
00268             delete m_activity->m_actioninfo;
00269             m_activity->m_actioninfo = NULL;
00270         }
00271         m_activity->m_actioninfo = new ActionInfo(m_object->getPather(), m_location);
00272         m_activity->m_actioninfo->m_action = m_object->getAction(action_name);
00273         if (!m_activity->m_actioninfo->m_action) {
00274             delete m_activity->m_actioninfo;
00275             m_activity->m_actioninfo = NULL;
00276             throw NotFound(std::string("action ") + action_name + " not found");
00277         }
00278         m_activity->m_actioninfo->m_prev_call_time = getRuntime();
00279         if (m_activity->m_actioninfo->m_action != old_action) {
00280             m_activity->m_actioninfo->m_action_start_time = m_activity->m_actioninfo->m_prev_call_time;
00281         }
00282     }
00283 
00284     void Instance::move(const std::string& action_name, const Location& target, const double speed) {
00285         initializeChanges();
00286         initializeAction(action_name);
00287         m_activity->m_actioninfo->m_target = new Location(target);
00288         m_activity->m_actioninfo->m_speed = speed;
00289         setFacingLocation(target);
00290         FL_DBG(_log, LMsg("starting action ") <<  action_name << " from" << m_location << " to " << target << " with speed " << speed);
00291     }
00292 
00293     void Instance::follow(const std::string& action_name, Instance* leader, const double speed) {
00294         initializeChanges();
00295         initializeAction(action_name);
00296         m_activity->m_actioninfo->m_target = new Location(leader->getLocationRef());
00297         m_activity->m_actioninfo->m_speed = speed;
00298         m_activity->m_actioninfo->m_leader = leader;
00299         leader->addDeleteListener(this);
00300         setFacingLocation(*m_activity->m_actioninfo->m_target);
00301         FL_DBG(_log, LMsg("starting action ") <<  action_name << " from" << m_location << " to " << *m_activity->m_actioninfo->m_target << " with speed " << speed);
00302     }
00303 
00304     void Instance::act(const std::string& action_name, const Location& direction, bool repeating) {
00305         initializeChanges();
00306         initializeAction(action_name);
00307         m_activity->m_actioninfo->m_repeating = repeating;
00308         setFacingLocation(direction);
00309     }
00310 
00311     void Instance::say(const std::string& text, unsigned int duration) {
00312         initializeChanges();
00313         delete m_activity->m_sayinfo;
00314         m_activity->m_sayinfo = NULL;
00315 
00316         if (text != "") {
00317             m_activity->m_sayinfo = new SayInfo(text, duration);
00318             m_activity->m_sayinfo->m_start_time = getRuntime();
00319         }
00320     }
00321 
00322     const std::string* Instance::getSayText() const {
00323         if (m_activity && m_activity->m_sayinfo) {
00324             return &m_activity->m_sayinfo->m_txt;
00325         }
00326         return NULL;
00327     }
00328 
00329     void Instance::setFacingLocation(const Location& loc) {
00330         if (!m_facinglocation) {
00331             m_facinglocation = new Location(loc);
00332         } else {
00333             *m_facinglocation = loc;
00334         }
00335     }
00336 
00337     bool Instance::process_movement() {
00338         FL_DBG(_log, "Moving...");
00339         ActionInfo* info = m_activity->m_actioninfo;
00340         // timeslice for this movement
00341         unsigned int timedelta = m_activity->m_timeprovider->getGameTime() - info->m_prev_call_time;
00342         FL_DBG(_log, LMsg("timedelta ") <<  timedelta << " prevcalltime " << info->m_prev_call_time);
00343         // how far we can travel
00344         double distance_to_travel = (static_cast<double>(timedelta) / 1000.0) * info->m_speed;
00345         FL_DBG(_log, LMsg("dist ") <<  distance_to_travel);
00346 
00347         Location nextLocation = m_location;
00348         info->m_pather_session_id = info->m_pather->getNextLocation(
00349             this, *info->m_target,
00350             distance_to_travel, nextLocation, *m_facinglocation,
00351             info->m_pather_session_id);
00352         m_location.getLayer()->getInstanceTree()->removeInstance(this);
00353         m_location = nextLocation;
00354         //ExactModelCoordinate a = nextLocation.getMapCoordinates();
00355         //ExactModelCoordinate b = m_actioninfo->m_target->getMapCoordinates();
00356         m_location.getLayer()->getInstanceTree()->addInstance(this);
00357         // return if we are close enough to target to stop
00358         if (info->m_pather_session_id == -1) {
00359             return true;
00360         }
00361         return false;
00362     }
00363 
00364     InstanceChangeInfo Instance::update() {
00365         if (!m_activity) {
00366             return ICHANGE_NO_CHANGES;
00367         }
00368         m_activity->update(*this);
00369         if (!m_activity->m_timeprovider) {
00370             bindTimeProvider();
00371         }
00372         ActionInfo* info = m_activity->m_actioninfo;
00373         if (info) {
00374             FL_DBG(_log, "updating instance");
00375 
00376             if (info->m_target) {
00377                 FL_DBG(_log, "action contains target for movement");
00378                 // update target if needed
00379                 if (info->m_leader && (info->m_leader->getLocationRef() != *info->m_target)) {
00380                     *info->m_target = info->m_leader->getLocation();
00381                 }
00382                 bool movement_finished = process_movement();
00383                 if (movement_finished) {
00384                     FL_DBG(_log, "movement finished");
00385                     finalizeAction();
00386                 }
00387             } else {
00388                 FL_DBG(_log, "action does not contain target for movement");
00389                 if (m_activity->m_timeprovider->getGameTime() - info->m_action_start_time + info->m_action_offset_time >= info->m_action->getDuration()) {
00390                     if (info->m_repeating) {
00391                         info->m_action_start_time = m_activity->m_timeprovider->getGameTime();
00392                         // prock: offset no longer needed
00393                         info->m_action_offset_time = 0;
00394                     } else {
00395                         finalizeAction();
00396                     }
00397                 }
00398             }
00399 
00400             // previous code may invalidate actioninfo.
00401             if( m_activity->m_actioninfo ) {
00402                 m_activity->m_actioninfo->m_prev_call_time = m_activity->m_timeprovider->getGameTime();
00403             }
00404         }
00405         if (m_activity->m_sayinfo) {
00406             if (m_activity->m_sayinfo->m_duration > 0) {
00407                 if (m_activity->m_timeprovider->getGameTime() >= m_activity->m_sayinfo->m_start_time + m_activity->m_sayinfo->m_duration) {
00408                     say("");
00409                 }
00410             }
00411         }
00412         return m_changeinfo;
00413     }
00414 
00415     void Instance::finalizeAction() {
00416         FL_DBG(_log, "finalizing action");
00417         assert(m_activity);
00418         assert(m_activity->m_actioninfo);
00419 
00420         if( m_activity->m_actioninfo->m_leader ) {
00421             m_activity->m_actioninfo->m_leader->removeDeleteListener(this);
00422         }
00423 
00424         Action* action = m_activity->m_actioninfo->m_action;
00425         delete m_activity->m_actioninfo;
00426         m_activity->m_actioninfo = NULL;
00427 
00428         std::vector<InstanceActionListener*>::iterator i = m_activity->m_actionlisteners.begin();
00429         while (i != m_activity->m_actionlisteners.end()) {
00430             if(*i)
00431                 (*i)->onInstanceActionFinished(this, action);
00432             ++i;
00433         }
00434         m_activity->m_actionlisteners.erase(
00435             std::remove(m_activity->m_actionlisteners.begin(),
00436                 m_activity->m_actionlisteners.end(),
00437                 (InstanceActionListener*)NULL),
00438             m_activity->m_actionlisteners.end());
00439     }
00440 
00441     Action* Instance::getCurrentAction() const {
00442         if (m_activity && m_activity->m_actioninfo) {
00443             return m_activity->m_actioninfo->m_action;
00444         }
00445         return NULL;
00446     }
00447 
00448     Location Instance::getTargetLocation() const {
00449         if (m_activity && m_activity->m_actioninfo && m_activity->m_actioninfo->m_target) {
00450             return *m_activity->m_actioninfo->m_target;
00451         }
00452         return m_location;
00453     }
00454 
00455     double Instance::getMovementSpeed() const {
00456         if (m_activity && m_activity->m_actioninfo) {
00457             return m_activity->m_actioninfo->m_speed;
00458         }
00459         return 0;
00460     }
00461 
00462     Location Instance::getFacingLocation() {
00463         return this->getFacingLocationRef();
00464     }
00465 
00466     Location& Instance::getFacingLocationRef() {
00467         if (!m_facinglocation) {
00468             m_facinglocation = new Location(m_location);
00469             m_facinglocation->setExactLayerCoordinates(m_facinglocation->getExactLayerCoordinates() + ExactModelCoordinate(1.0, 0.0));
00470             //m_facinglocation->setLayerCoordinates(ModelCoordinate(1,0));
00471         }
00472         return *m_facinglocation;
00473     }
00474 
00475     unsigned int Instance::getActionRuntime() {
00476         if (m_activity && m_activity->m_actioninfo) {
00477             if(!m_activity->m_timeprovider)
00478                 bindTimeProvider();
00479             return m_activity->m_timeprovider->getGameTime() - m_activity->m_actioninfo->m_action_start_time + m_activity->m_actioninfo->m_action_offset_time;
00480         }
00481         return getRuntime();
00482     }
00483 
00484     void Instance::setActionRuntime(unsigned int time_offset) {
00485         m_activity->m_actioninfo->m_action_offset_time = time_offset;
00486     }
00487 
00488     void Instance::bindTimeProvider() {
00489         float multiplier = 1.0;
00490         if (m_activity->m_timeprovider) {
00491             multiplier = m_activity->m_timeprovider->getMultiplier();
00492         }
00493         delete m_activity->m_timeprovider;
00494         m_activity->m_timeprovider = NULL;
00495 
00496         if (m_location.getLayer()) {
00497             Map* map = m_location.getLayer()->getMap();
00498             if (map) {
00499                 m_activity->m_timeprovider = new TimeProvider(map->getTimeProvider());
00500             }
00501         }
00502         if (!m_activity->m_timeprovider) {
00503             m_activity->m_timeprovider = new TimeProvider(NULL);
00504         }
00505         m_activity->m_timeprovider->setMultiplier(multiplier);
00506     }
00507 
00508     void Instance::refresh() {
00509         initializeChanges();
00510         bindTimeProvider();
00511     }
00512 
00513     void Instance::setTimeMultiplier(float multip) {
00514         initializeChanges();
00515         if (!m_activity->m_timeprovider) {
00516             bindTimeProvider();
00517         }
00518         m_activity->m_timeprovider->setMultiplier(multip);
00519     }
00520 
00521     float Instance::getTimeMultiplier() {
00522         if (m_activity && m_activity->m_timeprovider) {
00523             return m_activity->m_timeprovider->getMultiplier();
00524         }
00525         return 1.0;
00526     }
00527 
00528     float Instance::getTotalTimeMultiplier() {
00529         if (m_activity && m_activity->m_timeprovider) {
00530             return m_activity->m_timeprovider->getTotalMultiplier();
00531         }
00532         if (m_location.getLayer()) {
00533             Map* map = m_location.getLayer()->getMap();
00534             if (map && map->getTimeProvider()) {
00535                 return map->getTimeProvider()->getTotalMultiplier();
00536             }
00537         }
00538         return 1.0;
00539     }
00540 
00541     unsigned int Instance::getRuntime() {
00542         if (m_activity) {
00543             if(!m_activity->m_timeprovider)
00544                 bindTimeProvider();
00545             return m_activity->m_timeprovider->getGameTime();
00546         }
00547         if (m_location.getLayer()) {
00548             Map* map = m_location.getLayer()->getMap();
00549             if (map && map->getTimeProvider()) {
00550                 return map->getTimeProvider()->getGameTime();
00551             }
00552         }
00553         return TimeManager::instance()->getTime();
00554     }
00555         void Instance::addDeleteListener(InstanceDeleteListener *listener) {
00556                 m_deletelisteners.push_back(listener);
00557         }
00558         void Instance::removeDeleteListener(InstanceDeleteListener *listener) {
00559                 std::vector<InstanceDeleteListener*>::iterator itor;
00560                 itor = std::find(m_deletelisteners.begin(),
00561                                  m_deletelisteners.end(),
00562                                  listener);
00563                 if(itor != m_deletelisteners.end()) {
00564                         m_deletelisteners.erase(itor);
00565                 } else {
00566                         FL_WARN(_log, "Cannot remove unknown listener");
00567                 }
00568         }
00569         void Instance::onInstanceDeleted(Instance* instance) {
00570                 if(m_activity && 
00571                    m_activity->m_actioninfo && 
00572                    m_activity->m_actioninfo->m_leader == instance) {
00573                         m_activity->m_actioninfo->m_leader = NULL;
00574                 }
00575         }
00576 }