Mercurial > fife-parpg
view engine/core/model/structures/instance.cpp @ 46:90005975cdbb
* Final LGPL switch step by adjusting the file headers
* Remaining issues (just slightly related to the unittest switch):
* No working unittest solution for msvc2005 yet
* Unittests not working with mingw + scons either though this seems hard to impossible to fix without an expert in this field
* sample_unit_test.cpp would need to get modified for unittest++; it still contains the old boost unittest code
author | mvbarracuda@33b003aa-7bff-0310-803a-e67f0ece8222 |
---|---|
date | Sun, 13 Jul 2008 11:05:12 +0000 |
parents | 4a0efb7baf70 |
children | 64e7fe3d4288 |
line wrap: on
line source
/*************************************************************************** * Copyright (C) 2005-2008 by the FIFE team * * http://www.fifengine.de * * This file is part of FIFE. * * * * FIFE is free software; you can redistribute it and/or * * modify it under the terms of the GNU Lesser General Public * * License as published by the Free Software Foundation; either * * version 2.1 of the License, or (at your option) any later version. * * * * This library is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * ***************************************************************************/ // Standard C++ library includes #include <iostream> // 3rd party library includes #include <SDL.h> // FIFE includes // These includes are split up in two parts, separated by one empty line // First block: files included from the FIFE root src directory // Second block: files included from the same folder #include "util/log/logger.h" #include "util/base/exception.h" #include "util/math/fife_math.h" #include "model/metamodel/grids/cellgrid.h" #include "model/metamodel/abstractpather.h" #include "model/metamodel/action.h" #include "model/metamodel/timeprovider.h" #include "model/structures/layer.h" #include "model/structures/map.h" #include "model/structures/instancetree.h" #include "instance.h" namespace FIFE { static Logger _log(LM_INSTANCE); class ActionInfo { public: ActionInfo(AbstractPather* pather, const Location& curloc): m_action(NULL), m_target(NULL), m_speed(0), m_repeating(false), m_action_start_time(SDL_GetTicks()), m_prev_call_time(m_action_start_time), m_pather_session_id(-1), m_pather(pather), m_leader(NULL) {} ~ActionInfo() { if (m_pather_session_id != -1) { m_pather->cancelSession(m_pather_session_id); } delete m_target; m_target = NULL; } // Current action, owned by object Action* m_action; // target location for ongoing movement Location* m_target; // current movement speed double m_speed; // should action be repeated? used only for non-moving actions, moving ones repeat until movement is finished bool m_repeating; // action start time (ticks) unsigned int m_action_start_time; // ticks since last call unsigned int m_prev_call_time; // current time for action processing (set by Instance::update), optimized to avoid multiple calls to GetTicks unsigned int m_cur_time; // session id for pather int m_pather_session_id; // pather AbstractPather* m_pather; // leader for follow activity Instance* m_leader; }; class SayInfo { public: SayInfo(const std::string& txt, unsigned int duration): m_txt(txt), m_duration(duration), m_start_time(SDL_GetTicks()) { } std::string m_txt; unsigned int m_duration; unsigned int m_start_time; }; Instance::InstanceActivity::InstanceActivity(Instance& source): m_location(source.m_location), m_facinglocation(), m_action(), m_speed(0), m_timemultiplier(1.0), m_saytxt(""), m_changelisteners(), m_actionlisteners(), m_actioninfo(NULL), m_sayinfo(NULL), m_timeprovider(NULL) { if (source.m_facinglocation) { m_facinglocation = *source.m_facinglocation; } } Instance::InstanceActivity::~InstanceActivity() { delete m_actioninfo; delete m_sayinfo; delete m_timeprovider; } void Instance::InstanceActivity::update(Instance& source) { source.m_changeinfo = ICHANGE_NO_CHANGES; if (m_location != source.m_location) { source.m_changeinfo |= ICHANGE_LOC; m_location = source.m_location; } if (source.m_facinglocation && (m_facinglocation != *source.m_facinglocation)) { source.m_changeinfo |= ICHANGE_FACING_LOC; m_facinglocation = *source.m_facinglocation; } if (m_actioninfo && (m_speed != m_actioninfo->m_speed)) { source.m_changeinfo |= ICHANGE_SPEED; m_speed = m_actioninfo->m_speed; } if (m_actioninfo && (m_action != m_actioninfo->m_action)) { source.m_changeinfo |= ICHANGE_ACTION; m_action = m_actioninfo->m_action; } if (m_timeprovider && (m_timemultiplier != m_timeprovider->getMultiplier())) { source.m_changeinfo |= ICHANGE_TIME_MULTIPLIER; m_timemultiplier = m_timeprovider->getMultiplier(); } if (m_sayinfo && (m_saytxt != m_sayinfo->m_txt)) { source.m_changeinfo |= ICHANGE_SAYTEXT; m_saytxt = m_sayinfo->m_txt; } if (source.m_changeinfo != ICHANGE_NO_CHANGES) { std::vector<InstanceChangeListener*>::iterator i = m_changelisteners.begin(); while (i != m_changelisteners.end()) { (*i)->onInstanceChanged(&source, source.m_changeinfo); ++i; } } } Instance::Instance(Object* object, const Location& location, const std::string& identifier): m_id(identifier), m_rotation(0), m_activity(NULL), m_changeinfo(ICHANGE_NO_CHANGES), m_object(object), m_location(location), m_facinglocation(NULL), m_visual(NULL) { } Instance::~Instance() { delete m_activity; delete m_facinglocation; delete m_visual; } void Instance::initializeChanges() { if (!m_activity) { m_activity = new InstanceActivity(*this); } } void Instance::setLocation(const Location& loc) { initializeChanges(); m_location = loc; bindTimeProvider(); } void Instance::setRotation(int rotation) { m_rotation = rotation; m_changeinfo |= ICHANGE_ROTATION; } void Instance::addActionListener(InstanceActionListener* listener) { initializeChanges(); m_activity->m_actionlisteners.push_back(listener); } void Instance::removeActionListener(InstanceActionListener* listener) { if (!m_activity) { return; } std::vector<InstanceActionListener*>::iterator i = m_activity->m_actionlisteners.begin(); while (i != m_activity->m_actionlisteners.end()) { if ((*i) == listener) { m_activity->m_actionlisteners.erase(i); return; } ++i; } FL_WARN(_log, "Cannot remove unknown listener"); } void Instance::addChangeListener(InstanceChangeListener* listener) { initializeChanges(); m_activity->m_changelisteners.push_back(listener); } void Instance::removeChangeListener(InstanceChangeListener* listener) { if (!m_activity) { return; } std::vector<InstanceChangeListener*>::iterator i = m_activity->m_changelisteners.begin(); while (i != m_activity->m_changelisteners.end()) { if ((*i) == listener) { m_activity->m_changelisteners.erase(i); return; } ++i; } FL_WARN(_log, "Cannot remove unknown listener"); } void Instance::initalizeAction(const std::string& action_name) { assert(m_object); assert(m_activity); if (m_activity->m_actioninfo) { delete m_activity->m_actioninfo; m_activity->m_actioninfo = NULL; } m_activity->m_actioninfo = new ActionInfo(m_object->getPather(), m_location); m_activity->m_actioninfo->m_action = m_object->getAction(action_name); if (!m_activity->m_actioninfo->m_action) { delete m_activity->m_actioninfo; m_activity->m_actioninfo = NULL; throw NotFound(std::string("action ") + action_name + " not found"); } } void Instance::move(const std::string& action_name, const Location& target, const double speed) { initializeChanges(); initalizeAction(action_name); m_activity->m_actioninfo->m_target = new Location(target); m_activity->m_actioninfo->m_speed = speed; setFacingLocation(target); FL_DBG(_log, LMsg("starting action ") << action_name << " from" << m_location << " to " << target << " with speed " << speed); } void Instance::follow(const std::string& action_name, Instance* leader, const double speed) { initializeChanges(); initalizeAction(action_name); m_activity->m_actioninfo->m_target = new Location(leader->getLocationRef()); m_activity->m_actioninfo->m_speed = speed; m_activity->m_actioninfo->m_leader = leader; setFacingLocation(*m_activity->m_actioninfo->m_target); FL_DBG(_log, LMsg("starting action ") << action_name << " from" << m_location << " to " << *m_activity->m_actioninfo->m_target << " with speed " << speed); } void Instance::act(const std::string& action_name, const Location& direction, bool repeating) { initializeChanges(); initalizeAction(action_name); m_activity->m_actioninfo->m_repeating = repeating; setFacingLocation(direction); } void Instance::say(const std::string& text, unsigned int duration) { initializeChanges(); delete m_activity->m_sayinfo; m_activity->m_sayinfo = NULL; if (text != "") { m_activity->m_sayinfo = new SayInfo(text, duration); } } const std::string* Instance::getSayText() const { if (m_activity && m_activity->m_sayinfo) { return &m_activity->m_sayinfo->m_txt; } return NULL; } void Instance::setFacingLocation(const Location& loc) { if (!m_facinglocation) { m_facinglocation = new Location(loc); } else { *m_facinglocation = loc; } } bool Instance::process_movement() { FL_DBG(_log, "Moving..."); ActionInfo* info = m_activity->m_actioninfo; // timeslice for this movement unsigned int timedelta = scaleTime(getTotalTimeMultiplier(), info->m_cur_time - info->m_prev_call_time); FL_DBG(_log, LMsg("timedelta ") << timedelta << " prevcalltime " << info->m_prev_call_time); // how far we can travel double distance_to_travel = (static_cast<double>(timedelta) / 1000.0) * info->m_speed; FL_DBG(_log, LMsg("dist ") << distance_to_travel); Location nextLocation = m_location; info->m_pather_session_id = info->m_pather->getNextLocation( this, *info->m_target, distance_to_travel, nextLocation, *m_facinglocation, info->m_pather_session_id); m_location.getLayer()->getInstanceTree()->removeInstance(this); m_location = nextLocation; //ExactModelCoordinate a = nextLocation.getMapCoordinates(); //ExactModelCoordinate b = m_actioninfo->m_target->getMapCoordinates(); m_location.getLayer()->getInstanceTree()->addInstance(this); // return if we are close enough to target to stop if (info->m_pather_session_id == -1) { return true; } return false; } InstanceChangeInfo Instance::update(unsigned int curticks) { if (!m_activity) { return ICHANGE_NO_CHANGES; } m_activity->update(*this); if (!m_activity->m_timeprovider) { bindTimeProvider(); } if (curticks == 0) { curticks = SDL_GetTicks(); } ActionInfo* info = m_activity->m_actioninfo; if (info) { info->m_cur_time = curticks; FL_DBG(_log, LMsg("updating instance, ticks = ") << curticks); if (info->m_target) { FL_DBG(_log, "action contains target for movement"); // update target if needed if (info->m_leader && (info->m_leader->getLocationRef() != *info->m_target)) { *info->m_target = info->m_leader->getLocation(); } bool movement_finished = process_movement(); if (movement_finished) { FL_DBG(_log, "movement finished"); finalizeAction(); } } else { FL_DBG(_log, "action does not contain target for movement"); if (scaleTime(getTotalTimeMultiplier(), curticks - info->m_action_start_time) >= info->m_action->getDuration()) { if (info->m_repeating) { info->m_action_start_time = curticks; } else { finalizeAction(); } } } m_activity->m_actioninfo->m_prev_call_time = curticks; } if (m_activity->m_sayinfo) { if (m_activity->m_sayinfo->m_duration > 0) { if (scaleTime(getTotalTimeMultiplier(), curticks - m_activity->m_sayinfo->m_start_time) > m_activity->m_sayinfo->m_duration) { say(""); } } } return m_changeinfo; } void Instance::finalizeAction() { FL_DBG(_log, "finalizing action"); assert(m_activity); assert(m_activity->m_actioninfo); Action* action = m_activity->m_actioninfo->m_action; delete m_activity->m_actioninfo; m_activity->m_actioninfo = NULL; std::vector<InstanceActionListener*>::iterator i = m_activity->m_actionlisteners.begin(); while (i != m_activity->m_actionlisteners.end()) { (*i)->onInstanceActionFinished(this, action); ++i; } } Action* Instance::getCurrentAction() const { if (m_activity && m_activity->m_actioninfo) { return m_activity->m_actioninfo->m_action; } return NULL; } Location Instance::getTargetLocation() const { if (m_activity && m_activity->m_actioninfo && m_activity->m_actioninfo->m_target) { return *m_activity->m_actioninfo->m_target; } return m_location; } double Instance::getMovementSpeed() const { if (m_activity && m_activity->m_actioninfo) { return m_activity->m_actioninfo->m_speed; } return 0; } Location Instance::getFacingLocation() { return this->getFacingLocationRef(); } Location& Instance::getFacingLocationRef() { if (!m_facinglocation) { m_facinglocation = new Location(m_location); m_facinglocation->setExactLayerCoordinates(m_facinglocation->getExactLayerCoordinates() + ExactModelCoordinate(1.0, 0.0)); //m_facinglocation->setLayerCoordinates(ModelCoordinate(1,0)); } return *m_facinglocation; } int Instance::getActionRuntime() const { if (m_activity && m_activity->m_actioninfo) { return SDL_GetTicks() - m_activity->m_actioninfo->m_action_start_time; } return -1; } void Instance::bindTimeProvider() { float multiplier = 1.0; if (m_activity->m_timeprovider) { multiplier = m_activity->m_timeprovider->getMultiplier(); } delete m_activity->m_timeprovider; m_activity->m_timeprovider = NULL; if (m_location.getLayer()) { Map* map = m_location.getLayer()->getMap(); if (map) { m_activity->m_timeprovider = new TimeProvider(map->getTimeProvider()); } } if (!m_activity->m_timeprovider) { m_activity->m_timeprovider = new TimeProvider(NULL); } m_activity->m_timeprovider->setMultiplier(multiplier); } void Instance::refresh() { initializeChanges(); bindTimeProvider(); } void Instance::setTimeMultiplier(float multip) { initializeChanges(); if (!m_activity->m_timeprovider) { bindTimeProvider(); } m_activity->m_timeprovider->setMultiplier(multip); } float Instance::getTimeMultiplier() { if (m_activity && m_activity->m_timeprovider) { return m_activity->m_timeprovider->getMultiplier(); } return 1.0; } float Instance::getTotalTimeMultiplier() { if (m_activity && m_activity->m_timeprovider) { return m_activity->m_timeprovider->getTotalMultiplier(); } return 1.0; } }