CombatProcess.cpp

Go to the documentation of this file.
00001 /*
00002 Copyright (C) 2004-2007 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 
00021 #include "CombatProcess.h"
00022 #include "Actor.h"
00023 #include "CurrentMap.h"
00024 #include "World.h"
00025 #include "UCList.h"
00026 #include "LoopScript.h"
00027 #include "WeaponInfo.h"
00028 #include "AnimationTracker.h"
00029 #include "Kernel.h"
00030 #include "DelayProcess.h"
00031 #include "PathfinderProcess.h"
00032 #include "ShapeInfo.h"
00033 #include "MonsterInfo.h"
00034 #include "getObject.h"
00035 #include "LoiterProcess.h"
00036 #include "AmbushProcess.h"
00037 
00038 #include "IDataSource.h"
00039 #include "ODataSource.h"
00040 
00041 // p_dynamic_cast stuff
00042 DEFINE_RUNTIME_CLASSTYPE_CODE(CombatProcess,Process);
00043 
00044 CombatProcess::CombatProcess() : Process()
00045 {
00046 
00047 }
00048 
00049 CombatProcess::CombatProcess(Actor* actor_)
00050 {
00051         assert(actor_);
00052         item_num = actor_->getObjId();
00053 
00054         type = 0x00F2; // CONSTANT !
00055         target = 0;
00056         fixedTarget = 0;
00057         combatmode = CM_WAITING;
00058 }
00059 
00060 void CombatProcess::terminate()
00061 {
00062         Actor* a = getActor(item_num);
00063         if (a)
00064                 a->clearActorFlag(Actor::ACT_INCOMBAT);
00065 
00066         Process::terminate();
00067 }
00068 
00069 bool CombatProcess::run(const uint32 /*framenum*/)
00070 {
00071         Actor* a = getActor(item_num);
00072         if (!(a->getFlags() & Item::FLG_FASTAREA)) return false;
00073 
00074         Actor* t = getActor(target);
00075 
00076         if (!t || !isValidTarget(t)) {
00077                 // no target? try to find one
00078 
00079                 target = seekTarget();
00080 
00081                 if (!target) {
00082                         waitForTarget();
00083                         return false;
00084                 }
00085 
00086                 pout << "[COMBAT " << item_num << "] target found: "
00087                          << target << std::endl;
00088                 combatmode = CM_WAITING;
00089         }
00090 
00091         int targetdir = getTargetDirection();
00092         if (a->getDir() != targetdir) {
00093                 turnToDirection(targetdir);
00094                 return false;
00095         }
00096 
00097         if (inAttackRange()) {
00098                 combatmode = CM_ATTACKING;
00099 
00100                 pout << "[COMBAT " << item_num << "] target (" << target
00101                          << ") in range" << std::endl;
00102 
00103                 bool hasidle1 = a->hasAnim(Animation::idle1);
00104                 bool hasidle2 = a->hasAnim(Animation::idle2);
00105 
00106                 if ((hasidle1 || hasidle2) && (std::rand()%5) == 0) {
00107                         // every once in a while, act threatening instead of attacking
00108                         // TODO: maybe make frequency depend on monster type
00109                         Animation::Sequence idleanim;
00110 
00111                         if (!hasidle1) {
00112                                 idleanim = Animation::idle2;
00113                         } else if (!hasidle2) {
00114                                 idleanim = Animation::idle1;
00115                         } else {
00116                                 if (std::rand()%2)
00117                                         idleanim = Animation::idle1;
00118                                 else
00119                                         idleanim = Animation::idle2;
00120                         }
00121                         uint16 idlepid = a->doAnim(idleanim, 8);
00122                         waitFor(idlepid);                       
00123                 } else {
00124 
00125                         // attack
00126                         ProcId attackanim = a->doAnim(Animation::attack, 8);
00127 
00128                         // wait a while, depending on dexterity, before attacking again
00129                         int dex = a->getDex();
00130                         if (dex < 25) {
00131                                 int recoverytime = 3 * (25 - dex);
00132                                 Process* waitproc = new DelayProcess(recoverytime);
00133                                 ProcId waitpid = Kernel::get_instance()->addProcess(waitproc);
00134                                 waitproc->waitFor(attackanim);
00135                                 waitFor(waitpid);
00136                         } else {
00137                                 waitFor(attackanim);
00138                         }
00139                 }
00140 
00141                 return false;
00142         } else if (combatmode != CM_PATHFINDING) {
00143                 // not in range? See if we can get in range
00144 
00145                 Process* pfproc = new PathfinderProcess(a, target, true);
00146                 
00147                 waitFor(Kernel::get_instance()->addProcess(pfproc));
00148                 combatmode = CM_PATHFINDING;
00149                 return false;
00150         }
00151 
00152         combatmode = CM_WAITING;
00153         waitForTarget();
00154         return false;
00155 }
00156 
00157 ObjId CombatProcess::getTarget()
00158 {
00159         Actor* t = getActor(target);
00160 
00161         if (!t || !isValidTarget(t))
00162                 target = 0;
00163 
00164         return target;
00165 }
00166 
00167 void CombatProcess::setTarget(ObjId newtarget)
00168 {
00169         if (fixedTarget == 0) {
00170                 fixedTarget = newtarget; // want to prevent seekTarget from changing it
00171         }
00172 
00173         target = newtarget;
00174 }
00175 
00176 bool CombatProcess::isValidTarget(Actor* target)
00177 {
00178         assert(target);
00179         Actor* a = getActor(item_num);
00180         if (!a) return false; // uh oh
00181 
00182         // don't target self
00183         if (target == a) return false;
00184 
00185         // not in the fastarea
00186         if (!(target->getFlags() & Item::FLG_FASTAREA)) return false;
00187 
00188         // dead actors don't make good targets
00189         if (target->isDead()) return false;
00190 
00191         // feign death only works on undead and demons
00192         if (target->getActorFlags() & Actor::ACT_FEIGNDEATH) {
00193 
00194                 if ((a->getDefenseType() & WeaponInfo::DMG_UNDEAD) || 
00195                         (a->getShape() == 96)) return false; // CONSTANT!
00196         }
00197 
00198         // otherwise, ok
00199         return true;
00200 }
00201 
00202 bool CombatProcess::isEnemy(Actor* target)
00203 {
00204         assert(target);
00205 
00206         Actor* a = getActor(item_num);
00207         if (!a) return false; // uh oh
00208 
00209         return ((a->getEnemyAlignment() & target->getAlignment()) != 0);
00210 }
00211 
00212 ObjId CombatProcess::seekTarget()
00213 {
00214         Actor* a = getActor(item_num);
00215         if (!a) return 0; // uh oh
00216 
00217         if (fixedTarget) {
00218                 Actor* t = getActor(fixedTarget);
00219                 if (t && isValidTarget(t))
00220                         return fixedTarget; // no need to search
00221         }
00222 
00223         UCList itemlist(2);
00224         LOOPSCRIPT(script, LS_TOKEN_TRUE);
00225         CurrentMap* cm = World::get_instance()->getCurrentMap();
00226         cm->areaSearch(&itemlist, script, sizeof(script), a, 768, false);
00227 
00228         for (unsigned int i = 0; i < itemlist.getSize(); ++i) {
00229                 Actor* t = getActor(itemlist.getuint16(i));
00230 
00231                 if (t && isValidTarget(t) && isEnemy(t)) {
00232                         // found target
00233                         return itemlist.getuint16(i);
00234                 }
00235         }
00236 
00237         // no suitable targets
00238         return 0;
00239 }
00240 
00241 int CombatProcess::getTargetDirection()
00242 {
00243         Actor* a = getActor(item_num);
00244         Actor* t = getActor(target);
00245 
00246         return a->getDirToItemCentre(*t);
00247 }
00248 
00249 void CombatProcess::turnToDirection(int direction)
00250 {
00251         Actor* a = getActor(item_num);
00252         int curdir = a->getDir();
00253         int step = 1;
00254         if ((curdir - direction + 8) % 8 < 4) step = -1;
00255         Animation::Sequence turnanim = Animation::combatStand;
00256 
00257         ProcId prevpid = 0;
00258         bool done = false;
00259 
00260         for (int dir = curdir; !done; ) {
00261                 ProcId animpid = a->doAnim(turnanim, dir);
00262 
00263                 if (dir == direction) done = true;
00264 
00265                 if (prevpid) {
00266                         Process* proc = Kernel::get_instance()->getProcess(animpid);
00267                         assert(proc);
00268                         proc->waitFor(prevpid);
00269                 }
00270 
00271                 prevpid = animpid;
00272 
00273                 dir = (dir + step + 8) % 8;
00274         }
00275 
00276         if (prevpid) waitFor(prevpid);  
00277 }
00278 
00279 bool CombatProcess::inAttackRange()
00280 {
00281         Actor* a = getActor(item_num);
00282         ShapeInfo* shapeinfo = a->getShapeInfo();
00283         MonsterInfo* mi = 0;
00284         if (shapeinfo) mi = shapeinfo->monsterinfo;
00285 
00286         if (mi && mi->ranged)
00287                 return true; // ranged attacks (ghost's fireball) always in range
00288 
00289         AnimationTracker tracker;
00290         if (!tracker.init(a, Animation::attack, a->getDir(), 0))
00291                 return false;
00292 
00293         while (tracker.step()) {
00294                 if (tracker.hitSomething()) break;
00295         }
00296 
00297         ObjId hit = tracker.hitSomething();
00298         if (hit == target) return true;
00299 
00300         return false;
00301 }
00302 
00303 void CombatProcess::waitForTarget()
00304 {
00305         Actor* a = getActor(item_num);
00306         ShapeInfo* shapeinfo = a->getShapeInfo();
00307         MonsterInfo* mi = 0;
00308         if (shapeinfo) mi = shapeinfo->monsterinfo;
00309 
00310         if (mi && mi->shifter && a->getMapNum() != 43 && (std::rand()%2) == 0 ) {
00311                 // changelings (except the ones at the U8 endgame pentagram)
00312 
00313                 // shift into a tree if nobody is around
00314 
00315                 ProcId shift1pid = a->doAnim(static_cast<Animation::Sequence>(20), 8);
00316                 Process* ambushproc = new AmbushProcess(a);
00317                 ProcId ambushpid = Kernel::get_instance()->addProcess(ambushproc);
00318                 ProcId shift2pid = a->doAnim(static_cast<Animation::Sequence>(21), 8);
00319                 Process* shift2proc = Kernel::get_instance()->getProcess(shift2pid);
00320 
00321                 ambushproc->waitFor(shift1pid);
00322                 shift2proc->waitFor(ambushpid);
00323                 waitFor(shift2proc);
00324 
00325         } else {
00326                 waitFor(Kernel::get_instance()->addProcess(new LoiterProcess(a, 1)));
00327         }
00328 }
00329 
00330 void CombatProcess::dumpInfo()
00331 {
00332         Process::dumpInfo();
00333         pout << "Target: " << target << std::endl;
00334 }
00335 
00336 void CombatProcess::saveData(ODataSource* ods)
00337 {
00338         Process::saveData(ods);
00339 
00340         ods->write2(target);
00341         ods->write2(fixedTarget);
00342         ods->write1(static_cast<uint8>(combatmode));
00343 }
00344 
00345 bool CombatProcess::loadData(IDataSource* ids, uint32 version)
00346 {
00347         if (!Process::loadData(ids, version)) return false;
00348 
00349         target = ids->read2();
00350         fixedTarget = ids->read2();
00351         combatmode = static_cast<CombatMode>(ids->read1());
00352 
00353         return true;
00354 }

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