PathfinderProcess.cpp

Go to the documentation of this file.
00001 /*
00002 Copyright (C) 2003-2005 The Pentagram team
00003 
00004 This program is free software; you can redistribute it and/or
00005 modify it under the terms of the GNU General Public License
00006 as published by the Free Software Foundation; either version 2
00007 of the License, or (at your option) any later version.
00008 
00009 This program is distributed in the hope that it will be useful,
00010 but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012 GNU General Public License for more details.
00013 
00014 You should have received a copy of the GNU General Public License
00015 along with this program; if not, write to the Free Software
00016 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00017 */
00018 
00019 #include "pent_include.h"
00020 #include "PathfinderProcess.h"
00021 
00022 #include "Actor.h"
00023 #include "Pathfinder.h"
00024 #include "getObject.h"
00025 
00026 #include "IDataSource.h"
00027 #include "ODataSource.h"
00028 
00029 static const unsigned int PATH_OK = 1;
00030 static const unsigned int PATH_FAILED = 0;
00031 
00032 // p_dynamic_cast stuff
00033 DEFINE_RUNTIME_CLASSTYPE_CODE(PathfinderProcess,Process);
00034 
00035 PathfinderProcess::PathfinderProcess() : Process()
00036 {
00037 
00038 }
00039 
00040 PathfinderProcess::PathfinderProcess(Actor* actor_, ObjId item_, bool hit)
00041 {
00042         assert(actor_);
00043         item_num = actor_->getObjId();
00044         type = 0x0204; // CONSTANT !
00045 
00046 
00047         Item* item = getItem(item_);
00048         if (!item) {
00049                 perr << "PathfinderProcess: non-existent target" << std::endl;
00050                 // can't get there...
00051                 result = PATH_FAILED;
00052                 terminateDeferred();
00053                 return;
00054         }
00055 
00056         currentstep = 0;
00057         targetitem = item_;
00058         hitmode = hit;
00059         assert(targetitem);
00060 
00061         item->getLocation(targetx, targety, targetz);
00062 
00063         Pathfinder pf;
00064         pf.init(actor_);
00065         pf.setTarget(item, hit);
00066 
00067         bool ok = pf.pathfind(path);
00068 
00069         if (!ok) {
00070                 perr << "PathfinderProcess: actor " << item_num
00071                          << " failed to find path" << std::endl;
00072                 // can't get there...
00073                 result = PATH_FAILED;
00074                 terminateDeferred();
00075                 return;
00076         }
00077 
00078         // TODO: check if flag already set? kill other pathfinders?
00079         actor_->setActorFlag(Actor::ACT_PATHFINDING);
00080 }
00081 
00082 PathfinderProcess::PathfinderProcess(Actor* actor_,
00083                                                                          sint32 x, sint32 y, sint32 z)
00084 {
00085         assert(actor_);
00086         item_num = actor_->getObjId();
00087 
00088         targetx = x;
00089         targety = y;
00090         targetz = z;
00091         targetitem = 0;
00092 
00093         currentstep = 0;
00094 
00095         Pathfinder pf;
00096         pf.init(actor_);
00097         pf.setTarget(targetx, targety, targetz);
00098 
00099         bool ok = pf.pathfind(path);
00100 
00101         if (!ok) {
00102                 perr << "PathfinderProcess: actor " << item_num
00103                          << " failed to find path" << std::endl;
00104                 // can't get there...
00105                 result = PATH_FAILED;
00106                 terminateDeferred();
00107                 return;
00108         }
00109 
00110         // TODO: check if flag already set? kill other pathfinders?
00111         actor_->setActorFlag(Actor::ACT_PATHFINDING);
00112 }
00113 
00114 PathfinderProcess::~PathfinderProcess()
00115 {
00116 
00117 }
00118 
00119 void PathfinderProcess::terminate()
00120 {
00121         Actor* actor = getActor(item_num);
00122         if (actor) {
00123                 // TODO: only clear if it was set by us?
00124                 // (slightly more complicated if we kill other pathfinders on startup)
00125                 actor->clearActorFlag(Actor::ACT_PATHFINDING);
00126         }
00127 
00128         Process::terminate();
00129 }
00130 
00131 bool PathfinderProcess::run(const uint32 /*framenum*/)
00132 {
00133         Actor* actor = getActor(item_num);
00134         assert(actor);
00135         // if not in the fastarea, do nothing
00136         if (!(actor->getFlags() & Item::FLG_FASTAREA)) return false;
00137 
00138 
00139         bool ok = true;
00140 
00141         if (targetitem) {
00142                 sint32 curx,cury,curz;
00143                 Item* item = getItem(targetitem);
00144                 if (!item) {
00145                         perr << "PathfinderProcess: target missing" << std::endl;
00146                         result = PATH_FAILED;
00147                         terminate();
00148                         return false;
00149                 }
00150 
00151                 item->getLocation(curx, cury, curz);
00152                 if (abs(curx - targetx) >= 32 || abs(cury - targety) >= 32 ||
00153                         abs(curz - targetz) >= 8)
00154                 {
00155                         // target moved
00156                         ok = false;
00157                 }
00158         }
00159 
00160         if (ok && currentstep >= path.size()) {
00161                 // done
00162 #if 0
00163                 pout << "PathfinderProcess: done" << std::endl;
00164 #endif
00165                 result = PATH_OK;
00166                 terminate();
00167                 return false;
00168         }
00169 
00170         // try to take the next step
00171 
00172 #if 0
00173         pout << "PathfinderProcess: trying step" << std::endl;
00174 #endif
00175 
00176         // if actor is still animating for whatever reason, wait until he stopped
00177         // FIXME: this should happen before the pathfinder is actually called,
00178         // since the running animation may move the actor, which could break
00179         // the found path.
00180         if (actor->getActorFlags() & Actor::ACT_ANIMLOCK) {
00181                 perr << "PathfinderProcess: ANIMLOCK, waiting" << std::endl;
00182                 return false;
00183         }
00184 
00185         if (ok) {
00186                 ok = actor->tryAnim(path[currentstep].action,
00187                                                         path[currentstep].direction,
00188                                                         path[currentstep].steps) == Animation::SUCCESS;
00189         }
00190 
00191         if (!ok) {
00192 #if 0
00193                 pout << "PathfinderProcess: recalculating path" << std::endl;
00194 #endif
00195 
00196                 // need to redetermine path
00197                 ok = true;
00198                 Pathfinder pf;
00199                 pf.init(actor);
00200                 if (targetitem) {
00201                         Item* item = getItem(targetitem);
00202                         if (!item)
00203                                 ok = false;
00204                         else {
00205                                 if(hitmode && !actor->isInCombat()) {
00206                                         // Actor exited combat mode
00207                                         hitmode = false;
00208                                 }
00209                                 pf.setTarget(item, hitmode);
00210                                 item->getLocation(targetx, targety, targetz);
00211                         }
00212                 } else {
00213                         pf.setTarget(targetx, targety, targetz);
00214                 }
00215                 if (ok)
00216                         ok = pf.pathfind(path);
00217 
00218                 currentstep = 0;
00219                 if (!ok) {
00220                         perr << "PathfinderProcess: actor " << item_num
00221                                  << " failed to find path" << std::endl;
00222                         // can't get there anymore
00223                         result = PATH_FAILED;
00224                         terminate();
00225                         return false;
00226                 }
00227         }
00228 
00229         if (currentstep >= path.size()) {
00230 #if 0
00231                 pout << "PathfinderProcess: done" << std::endl;
00232 #endif
00233                 // done
00234                 result = PATH_OK;
00235                 terminate();
00236                 return false;
00237         }
00238 
00239         uint16 animpid = actor->doAnim(path[currentstep].action,
00240                                                                    path[currentstep].direction,
00241                                                                    path[currentstep].steps);
00242 #if 0
00243         pout << "PathfinderProcess(" << getPid() << "): taking step "
00244                  << path[currentstep].action << "," << path[currentstep].direction
00245                  << " (animpid=" << animpid << ")" << std::endl;
00246 #endif
00247         currentstep++;
00248 
00249         waitFor(animpid);
00250         return true;
00251 }
00252 
00253 void PathfinderProcess::saveData(ODataSource* ods)
00254 {
00255         Process::saveData(ods);
00256 
00257         ods->write2(targetitem);
00258         ods->write2(static_cast<uint16>(targetx));
00259         ods->write2(static_cast<uint16>(targety));
00260         ods->write2(static_cast<uint16>(targetz));
00261         ods->write1(hitmode ? 1 : 0);
00262         ods->write2(static_cast<uint16>(currentstep));
00263 
00264         ods->write2(static_cast<uint16>(path.size()));
00265         for (unsigned int i = 0; i < path.size(); ++i) {
00266                 ods->write2(static_cast<uint16>(path[i].action));
00267                 ods->write2(static_cast<uint16>(path[i].direction));
00268         }
00269 }
00270 
00271 bool PathfinderProcess::loadData(IDataSource* ids, uint32 version)
00272 {
00273         if (!Process::loadData(ids, version)) return false;
00274 
00275         targetitem = ids->read2();
00276         targetx = ids->read2();
00277         targety = ids->read2();
00278         targetz = ids->read2();
00279         hitmode = (ids->read1() != 0);
00280         currentstep = ids->read2();
00281 
00282         unsigned int pathsize = ids->read2();
00283         path.resize(pathsize);
00284         for (unsigned int i = 0; i < pathsize; ++i) {
00285                 path[i].action = static_cast<Animation::Sequence>(ids->read2());
00286                 path[i].direction = ids->read2();
00287         }
00288 
00289         return true;
00290 }

Generated on Fri Jul 27 22:27:29 2007 for pentagram by  doxygen 1.4.7